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 (KDF) 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 [OWASP, 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 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 input salt [params #:key-size key-size])  bytes?

  k : (or/c kdf-spec? kdf-impl?)
  input : bytes?
  salt : (or/c bytes? #f)
  params : (listof (list/c symbol? any/c)) = '()
  key-size : (or/c exact-nonnegative-integer? #f) = #f
Runs the KDF specified by k on input and salt and produces a derived key (or password hash) of length key-size bytes. Additional parameters such as iteration count are passed via params. If key-size is #f, then it must be given in params with the key 'key-size.

The input argument may be a password or passphrase, or it may be input keying material from a key agreement operation.

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. (Note that KDFs with optional salt do not treat #f as equivalent to #"", but to a digest-dependent string of zeros.)

The following parameters are recognized for (list 'pbkdf2 'hmac digest):

  • (list 'iterations iterations) number of iterations

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

The following parameters are recognized for 'argon2d, 'argon2i, and 'argon2id:

  • (list 'm m) the memory cost (in kb)

  • (list 't t) the time cost

  • (list 'p p) the parallelism

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

Examples:
> (kdf '(pbkdf2 hmac sha256)
       #"I am the eggman"
       (crypto-random-bytes 16)
       '((iterations 100000))
       #:key-size 32)

#"J\373h\310mfmh\266\345JWde\227\225\313Ub\201\332\1O\367f\201{\232\256\363z\330"

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

'(#"\36>\376\334H\331^\6\370\25\302gC2\362\26"

  #"t\4\236=\200\225\334\344\375\262&\374\267\225?b")

Changed in version 2.0 of package crypto-lib: Added #:key-size argument. Previously, key-size was always passed in params.

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 and PHC String 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).

See [OWASP] for parameter recommendations.

Examples:
> (define pwcred (pwhash 'argon2id #"mypassword" '((m 4096) (t 10) (p 1))))
> pwcred

"$argon2id$v=19$m=4096,t=10,p=1$dJPZCOuOJa3Foy6xCdYVLQ$1B/cNol5YfOkUKg3txiDzxR8gyyq9pyV4g6NP1x0krA"

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