6 Key Derivation and Password Hashing
A key derivation function can be used to derive keys from secret material that is not directly suitable for use as a key, such as a passphrase or the result of a key agreement algorithm. Differnt KDFs have different additional parameters such as work factors and context information fields.
KDFs with adjustable work factors are also used to store passwords [HtSSaP, DUB]. A KDF is preferable to a simple digest function (even with a salt) because the work factor can be chosen to make exhaustively searching the space of likely passwords (typically short and composed of alpha-numeric characters) costly.
There are two groups of KDF specifiers. The following KDFs have work factors and are suitable for producing keys from passwords and storing passwords:
(list 'pbkdf2 'hmac digest-spec) —
the PBKDF2 function from PKCS#5 [PKCS5] using HMAC of digest-spec (see digest-spec?). 'scrypt —
scrypt, with work factors for both time and memory [scrypt] 'argon2d, 'argon2i, 'argon2id —
variants of Argon2, designed primarily for password hashing [Argon2, PHC]
The following KDFs are suitable for producing keys from the results of key-agreement algorithms. They are not suitable for storing passwords.
(list 'hkdf digest-spec) —
the HKDF extract-then-expand function [HKDF] (list 'concat digest-spec) —
the Concatentation (also called One-Step) KDF from NIST SP 800-56C [SP800-56C] using a plain digest (list 'concat 'hmac digest-spec) —
the Concatentation KDF [SP800-56C] using HMAC-digest-spec (list 'sp800-108-counter 'hmac digest-spec), (list 'sp800-108-feedback 'hmac digest-spec), and (list 'sp800-108-double-pipeline 'hmac digest-spec) —
KDF constructions from NIST SP 800-108 [SP800-108]; this library only supports 32-bit counters and the standard ordering of components (list 'ans-x9.63 digest-spec) —
similar to the concatenation KDF but with a different order of components, defined by ANSI [X963]
Changed in version 1.3 of package crypto-lib: Added support for 'hkdf, 'concat, 'sp800-108-*, and 'ans-x9.63 algorithms.
procedure
k : kdf-spec?
factories : (or/c crypto-factory? (listof crypto-factory?)) = (crypto-factories)
procedure
k : (or/c kdf-spec? kdf-impl?) pass : bytes? salt : (or/c bytes? #f) params : (listof (list/c symbol? any/c)) = '()
The salt must be a bytestring (bytes?) except in the following cases: if the KDF is 'ans-x9.63, 'concat with a digest, 'sp800-108-counter, or 'sp800-108-double-pipeline, then salt must be #f; if the KDF is 'hkdf or 'concat with HMAC, then salt may be either #f or a bytestring.
The following parameters are recognized for (list 'pbkdf2 'hmac digest):
(list 'iterations iterations) —
number of iterations (list 'key-size key-size) —
the size of the output
In 2000 PKCS#5 [PKCS5] recommended a minimum of 1000 iterations; the iteration count should be exponentially larger today.
The following parameters are recognized for 'scrypt:
(list 'N N) —
the CPU/memory cost (list 'p p) —
the parallelization factor (list 'r r) —
the block size (list 'key-size key-size) —
the size of the output
In 2009 the original scrypt paper [scrypt] used parameters such as 214 to 220 for N, 1 for p, and 8 for r.
The following parameters are recognized for 'argon2d, 'argon2i, and 'argon2id:
(list 't t) —
the time cost (list 'm m) —
the memory cost (in kb) (list 'p p) —
the parallelism (list 'key-size key-size) – the size of the output
The following parameters are recognized for the 'hkdf, 'concat, 'sp800-108-*, and 'asn-x9.63 families of KDFs:
(list 'info info-bytes) —
additional contextual information; see [HKDF, SP800-56A, SP800-108] for recommendations regarding the contents and format of this field (list 'key-size key-size) —
the size of the output
> (kdf '(pbkdf2 hmac sha256) #"I am the eggman" (crypto-random-bytes 16) '((iterations 100000) (key-size 32))) #"M\275\226\361\355\272@\231\37\365}9\354<81$3O\256\270\331\346QFZ_5?9\312\5"
> (kdf 'argon2id #"I am the walrus" #"googoogjoob" '((t 100) (m 2048) (p 1) (key-size 32))) #"\30V\214|i\2072VE\242\345`+A\262\352Ni\230|6\365\227M\364\2\326y{\256\271\21"
> (define pre-key (.... do key agreement ....))
> (list (kdf '(hkdf sha256) pre-key #f '((info #"enc") (key-size 16))) (kdf '(hkdf sha256) pre-key #f '((info #"mac") (key-size 16))))
'(#"\265\361c&2\361\301\26\273\271\264\255\334\365\313\212"
#"\235\t\220s\246C\f\230if'\303M\210\314\236")
The config parameters are nearly the same as for kdf, with the following exceptions:
The 'scrypt algorithm requires a parameter 'ln specifying the log (base 2) of the iteration count, instead of the 'N parameter expected by the kdf function.
The 'key-size parameter is not allowed. This library always generates password hashes with 32 bytes of raw output (before encoding).
> (define pwcred (pwhash 'argon2id #"mypassword" '((t 1000) (m 4096) (p 1)))) > pwcred "$argon2id$v=19$m=4096,t=1000,p=1$m+clolnAitzUfS2LdXAecw$tk4bWb9R4qjzOexnJVVkdCdKjSaZIVzjD7x7QBKZGeE"
Added in version 1.2 of package crypto-lib.
procedure
(pwhash-verify k password pwh) → boolean?
k : (or/c kdf-impl? #f) password : bytes? pwh : string?
If k is a KDF implementation (kdf-impl?), pwh must have been generated with the same KDF algorithm (but not necessarily the same implementation); otherwise an exception is raised. If k is #f, then the KDF algorithm is extracted from pwh and the (crypto-factories) list is searched for an implementation; if no implementation is found an exception is raised.
> (pwhash-verify #f #"mypassword" pwcred) #t
> (pwhash-verify #f #"wildguess" pwcred) #f
Added in version 1.2 of package crypto-lib.
procedure
(pbkdf2-hmac di pass salt #:iterations iterations [ #:key-size key-size]) → bytes? di : digest-spec? pass : bytes? salt : bytes? iterations : exact-positive-integer? key-size : exact-positive-integer? = (digest-size di)
> (pbkdf2-hmac 'sha256 #"I am the walrus" #"abcd" #:iterations 100000) #"\aR>\"^\241\301\253f\v\237\310\263\330T\321\301\307|\212`\370\rD\347\f`{>\226c\371"
procedure
(scrypt pass salt #:N N [ #:p p #:r r #:key-size key-size]) → bytes? pass : bytes? salt : bytes? N : exact-positive-integer? p : exact-positive-integer? = 1 r : exact-positive-integer? = 8 key-size : exact-positive-integer? = 32
Bibliography
[OWASP] | “Password Storage Cheat Sheet.” https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet | |
[HtSSaP] | Coda Hale, “How to Safely Store a Password: Use bcrypt.” http://codahale.com/how-to-safely-store-a-password/ | |
[DUB] | Tony Arcieri, “Don’t Use bcrypt.” http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html | |
[PKCS5] | B. Kaliski, “PKCS #5: Password-Based Cryptography Specification.” https://tools.ietf.org/html/rfc2898 | |
[bcrypt] | Niels Provos and David Mazières, “A Future-Adaptable Password Scheme.” https://www.usenix.org/legacy/events/usenix99/provos.html | |
[scrypt] | Colin Percival, “The scrypt key derivation function.” http://www.tarsnap.com/scrypt.html | |
[Argon2] | Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich, “Argon2: the memory-hard function for password hashing and other applications.” https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf | |
[PHC] | “Password Hashing Competition.” https://password-hashing.net/ | |
[HKDF] | “RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF).” https://tools.ietf.org/html/rfc5869 | |
[SP800-56A] | “NIST Special Publication 800-56A Rev. 3: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography.” https://csrc.nist.gov/publications/detail/sp/800-56a/rev-3/final | |
[SP800-56C] | “NIST Special Publication 800-56C Rev. 1: Recommendation for Key-Derivation Methods in Key-Establishment Schemes.” https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final | |
[SP800-108] | “NIST Special Publication 800-108: Recommendation for Key Derivation Using Pseudorandom Functions (Revised).” https://csrc.nist.gov/publications/detail/sp/800-108/final | |
[X963] | “Public Key Cryptography for the Financial Services Industry - Key Agreement and Key Transport Using Elliptic Curve Cryptography.” — |