On this page:
kdf-spec?
kdf-impl?
get-kdf
kdf
pwhash
pwhash-verify
pbkdf2-hmac
scrypt
Bibliography

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.

procedure

(kdf-spec? v)  boolean?

  v : any/c
Returns #t if v is a KDF specifier, #f otherwise.

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

(kdf-impl? v)  boolean?

  v : any/c
Returns #t if v is an implementation of a key-derivation function, #f otherwise.

procedure

(get-kdf k [factories])  (or/c kdf-impl? #f)

  k : kdf-spec?
  factories : (or/c crypto-factory? (listof crypto-factory?))
   = (crypto-factories)
Returns an implementation of KDF k from the given factories. If no factory in factories implements k, returns #f.

procedure

(kdf k pass salt [params])  bytes?

  k : (or/c kdf-spec? kdf-impl?)
  pass : bytes?
  salt : (or/c bytes? #f)
  params : (listof (list/c symbol? any/c)) = '()
Runs the KDF specified by k on the password or passphrase pass and the given salt and produces a derived key (or password hash). Additional parameters such as iteration count are passed via params.

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

Examples:
> (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")

procedure

(pwhash k password config)  string?

  k : (or/c kdf-spec? kdf-impl?)
  password : bytes?
  config : (listof (list/c symbol? any/c))
Computes a “password hash” from password suitable for storage, using the KDF algorithm k. The resulting string contains an identifier for the algorithm as well as the parameters from config. The result also contains an automatically generated salt. The formats are intended to be compatible with Modular Crypt Format.

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).

Examples:
> (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?
Check password against the password hash pwh.

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.

Examples:
> (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)
Finds an implementation of PBKDF2-HMAC-di using (crypto-factories) and uses it to derive a key of key-size bytes from pass and salt. The iterations argument controls the amount of work done.

Example:
> (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
Finds an implementation of scrypt [scrypt] using (crypto-factories) and uses it to derive a key of key-size bytes from pass and salt. The N parameter specifies the cost factor (affecting both CPU and memory resources).

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.” — Not freely available. The KDF definition can be found in Section 3.6.1 of [SEC1].