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 a secret key from a master secret such as a passphrase. Typically, KDFs have additional parameters such as salts and work factors.

KDFs 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. Different KDFs have different parameters, which may control time or space requirements.

procedure

(kdf-spec? v)  boolean?

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

A KDF specifier is one of the following:

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 : bytes?
  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 following parameters are recognized for (list 'pbkdf2 'hmac digest):

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:

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:

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

#"^\225?\a\315A\366\245\205\3A\207?\233_\235E\316\304\275\373\252\207\362\260\3518\v\240\a\243m"

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

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 formats are intended to be compatible with Modular Crypt Format.

The config parameters are nearly the same as for kdf, with the following exceptions:

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

"$argon2id$v=19$m=4096,t=1000,p=1$ZDVdF0LT1XFZ+5vcNtNBxA$S+5b8J57xaqdtK37F4E4Bgmgd/4STtd6JeuFjSI7n9k"

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/