This module provides an interface to the Argon2 reference C implementation. It depends on libargon2, and can be used dynamically with the shared library or statically compiled with the static library. The aim is to provide a high-level and fully-featured implementation of the C reference backed by comprehensive documentation, tests, and fuzzing.
Basic usage
The basic flow of using this module which mimicks the argon2 cli is:
- Set the wanted Argon2 hash parameters
- Set a password and salt
- Call getOutput with the previous parameters
- Verify the encoded portion of the returned object via isVerified
- Utilize the verified output
Example
import argon2_bind const params = setupArgon2Params( timeCost = 3, memoryCostK = 1 shl 8, parallelism = 2, algoType = Argon2id, ) const salt = "somesalt" var pass = "password" var res: Argon2Output try: res = pass.getOutput(salt, params) except Argon2Error: echo getCurrentExceptionMsg() quit 1 if res.encoded.isVerified(pass): echo res.hash # Output: # @[163, 22, 29, 233, 157, 14, 124, 7, 98, 54, 75, 44, 75, 62, 162, 185, # 80, 0, 89, 115, 248, 135, 157, 84, 40, 127, 216, 189, 86, 146, 31, 54]
Types
Argon2Error = object of CatchableError
- Catchable error arising from argon2_bind module. Source Edit
Argon2Type = enum Argon2d, Argon2i, Argon2id
-
Hashing algorithm variants available.
Argon2d is faster and uses data-depending memory access, which makes it highly resistant against GPU cracking attacks and suitable for applications with no threats from side-channel timing attacks (eg. cryptocurrencies). Argon2i instead uses data-independent memory access, which is preferred for password hashing and password-based key derivation, but it is slower as it makes more passes over the memory to protect from tradeoff attacks. Argon2id is a hybrid of Argon2i and Argon2d, using a combination of data-depending and data-independent memory accesses, which gives some of Argon2i's resistance to side-channel cache timing attacks and much of Argon2d's resistance to GPU cracking attacks.
Source Edit Argon2Version = enum Argon2Version10 = 0x00000010, Argon2Version13 = 0x00000013
-
Hashing algorithm version.
See also:
Source Edit Argon2Params {...}{.bycopy.} = object timeCost*, memoryCostK*, parallelism*, hashLen*: uint32 algoType*: Argon2Type version*: Argon2Version
-
Hashing parameters required to be passed.
Constraints
timeCost must be at least 1.
memoryCostK is in KiB, and the minimum must adhere to the formula memoryCostK/parallelism >= 8.
parallelism refers to the lanes and threads to be utilized. As mentioned via the memoryCostK constraint, each lane must have 8KiB of memory available to it.
hashLen minimum is 4.
See also:
Source Edit Argon2Output = object hash*: seq[byte] encoded*: string
-
hash will contain the finalized hash value as a sequence of bytes.
encoded key will contain the ad-hoc encoded output as a string. It is basically a stringified structure of all parameters, excluding the password, but including the hash value as the last variable in base64.
See also:
Source Edit
Consts
Argon2CurrentVersion = Argon2Version13
-
Denotes the current version, which is the one recommended to be used.
Output will of course differ between each version, keep note of the
version used. It is also noted in the encoded output.
See also:
Source Edit Argon2DefaultParams = (timeCost: 3'u, memoryCostK: 4096'u, parallelism: 1'u, hashLen: 32'u, algoType: Argon2i, version: Argon2Version13)
-
The default parameters to be utilized by the module. Utilized as a fallback in linked functions below.
These values match the current argon2 cli defaults.
See also:
Source Edit
Funcs
func setupArgon2Params(timeCost: uint32 = Argon2DefaultParams.timeCost; memoryCostK: uint32 = Argon2DefaultParams.memoryCostK; parallelism: uint32 = Argon2DefaultParams.parallelism; hashLen: uint32 = Argon2DefaultParams.hashLen; algoType: Argon2Type = Argon2DefaultParams.algoType; version: Argon2Version = Argon2DefaultParams.version): Argon2Params {...}{. inline, raises: [], tags: [].}
-
Returns the parameterized state needed by the hashing function, with each passed parameter being optional and having a fallback to the defaults if omitted.
See also:
Examples:
let firstParams = setupArgon2Params() doAssert firstParams == Argon2DefaultParams let secondParams = setupArgon2Params(hashLen = 4, memoryCostK = 1 shl 9) doAssert secondParams == Argon2Params(timeCost: 3, memoryCostK: 1 shl 9, parallelism: 1, hashLen: 4, algoType: Argon2i, version: Argon2CurrentVersion)
Source Edit func getEncodedLen(argon2Params: Argon2Params; salt: seq[byte] | string): uint32 {...}{. inline.}
-
Requires parameterized argon2 object.
Requires a salt parameter as either a byte sequence or string.
Returns the expected encoded output length, depending on input parameters.
Mainly for internal use.
Source Edit func getOutput(pass, salt: seq[byte] | string; argon2Params: Argon2Params = Argon2DefaultParams): Argon2Output {...}{. inline, raises: [Argon2Error].}
-
Requires a password and salt, either as a sequence of bytes or string. The password must have at least 1 byte. The salt must be at least 8 bytes.
Optionally takes the typed parameters for argon2, does a fallback to Argon2DefaultParams if none are passed. Only at this point are the parameters sanity checked, in their pass to the C lib.
Returns an Argon2Output object.
Raises an Argon2Error on internal exception.
See also:
Examples:
let params = setupArgon2Params(hashLen = 4) salt = "somesalt" pass = "abc" let res = pass.getOutput(salt, params) doAssert res.hash == @[27.byte, 96, 149, 111] doAssert res.encoded == "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$G2CVbw"
Source Edit func getRawHash(pass, salt: seq[byte] | string; argon2Params: Argon2Params = Argon2DefaultParams): seq[byte] {...}{.inline, raises: [Argon2Error].}
-
Refer to getOutput for input parameters which are shared here.
Returns a byte sequence of the computed hash value.
Raises an Argon2Error on internal exception.
See also:
Examples:
let params = setupArgon2Params(hashLen = 4) salt = "somesalt" pass = "abc" let res = pass.getRawHash(salt, params) doAssert res == @[27.byte, 96, 149, 111]
Source Edit func getEncodedHash(pass, salt: seq[byte] | string; argon2Params: Argon2Params = Argon2DefaultParams): string {...}{. inline, raises: [Argon2Error].}
-
Refer to getOutput for guidance on the input parameters.
Returns a string of the argon2 encoded value. Note, this is not the hash value.
Raises an Argon2Error on internal exception.
See also:
Examples:
var expected = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ" expected &= "$vi0N5Av/NnxgttHDWyVte+OheXu6wuyyFSWJsNEhCCI" let salt = "somesalt" pass = "abc" let res = pass.getEncodedHash(salt) doAssert res == expected let params = setupArgon2Params(hashLen = 4) let res2 = pass.getEncodedHash(salt, params) doAssert res2 == "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$G2CVbw"
Source Edit func isVerified(encoded: string; pass: seq[byte] | string): bool {...}{.inline, raises: [Argon2Error].}
-
Requires the encoded hash output as a string from either getEncodedHash or getOutput. Requires password of type byte sequence or string. Must be at least 1 byte.
Returns a bool, with true indicating success.
Raises an Argon2Error on internal exception.
Examples:
let pass = "pass" let encodedHash = getEncodedHash(pass, "somesalt") doAssert encodedHash.isVerified(pass) == true doAssert encodedHash.isVerified("wrongpass") == false try: discard encodedHash[0 .. ^2].isVerified(pass) doAssert false except Argon2Error: doAssert true except: doAssert false
Source Edit