Key derivation
Deriving a key from a password
Secret keys used to encrypt or sign confidential data have to be chosen from a very large keyspace. However, passwords are usually short, human-generated strings, making dictionary attacks practical.
The pwhash
operation derives a secret key of any size from a password and a salt.
Refer to the Password hashing section for more information and code examples.
Deriving keys from a single high-entropy key
Multiple secret subkeys can be derived from a single master key.
Given the master key and a key identifier, a subkey can be deterministically computed. However, given a subkey, an attacker cannot compute the master key nor any other subkeys.
Key derivation with libsodium >= 1.0.12
Recent versions of the library have a dedicated API for key derivation.
The crypto_kdf
API can derive up to 2^64 keys from a single master key and context, and individual subkeys can have an arbitrary length between 128 (16 bytes) and 512 bits (64 bytes).
Example:
Usage:
The crypto_kdf_keygen()
function creates a master key.
The crypto_kdf_derive_from_key()
function derives a subkey_id
-th subkey subkey
of length subkey_len
bytes using the master key key
and the context ctx
.
subkey_id
can be any value up to (2^64)-1
.
subkey_len
has to be between crypto_kdf_BYTES_MIN
(inclusive) and crypto_kdf_BYTES_MAX
(inclusive).
Similar to a type, the context ctx
is a 8 characters string describing what the key is going to be used for.
Its purpose is to mitigate accidental bugs by separating domains. The same function used with the same key but in two distinct contexts is likely to generate two different outputs.
Contexts don't have to be secret and can have a low entropy.
Examples of contexts include UserName
, __auth__
, pictures
and userdata
.
If more convenient, it is also fine to use a single global context for a whole application. This will still prevent the same keys from being mistakenly used by another application.
Constants:
crypto_kdf_PRIMITIVE
crypto_kdf_BYTES_MIN
crypto_kdf_BYTES_MAX
crypto_kdf_CONTEXTBYTES
crypto_kdf_KEYBYTES
Algorithm details:
BLAKE2B-subkeylen(key=key, message={}, salt=subkey_id || {0}, personal=ctx || {0})
Key derivation with libsodium < 1.0.12
On older versions of the library, the BLAKE2 function can be used directly:
The crypto_generichash_blake2b_salt_personal()
function can be used to derive a subkey of any size from a key of any size, as long as these key sizes are in the 128 to 512 bits interval.
In this example, two subkeys are derived from a single key. These subkeys have different sizes (128 and 256 bits), and are derived from a master key of yet another size (512 bits).
The personalization parameter (appid
) is a 16-bytes value that doesn't have to be secret. It can be used so that the same (masterkey, keyid)
tuple will produce different output in different applications. It is not required, however: a NULL
pointer can be passed instead in order to use the default constant.
The salt (keyid
) doesn't have to be secret either. This is a 16-bytes identifier, that can be a simple counter, and is used to derive more than one key out of a single master key.
Nonce extension
Unlike XSalsa20 (used by crypto_box_*
and crypto_secretbox_*
) and XChaCha20, ciphers such as AES-GCM and ChaCha20 require a nonce too short to be chosen randomly (64 or 96 bits). With 96 bits random nonces, 2^32 encryptions is the limit before the probability of duplicate nonces becomes too high.
Using a counter instead of random nonces prevents this. However, keeping a state is not always an option, especially with offline protocols.
As an alternative, the nonce can be extended: a key and a part of a long nonce are used as inputs to a pseudorandom function to compute a new key. This subkey and the remaining bits of the long nonce can then be used as parameters for the cipher.
For example, this allows using a 192-bits nonce with a cipher requiring a 64-bits nonce:
Since version 1.0.9, Sodium provides the crypto_core_hchacha20()
function, which can be used as a PRF for that purpose:
This function accepts a 32 bytes (crypto_core_hchacha20_KEYBYTES
) secret key k
as well as a 16 bytes (crypto_core_hchacha20_INPUTBYTES
) input in
, and outputs a 32 bytes (crypto_core_hchacha20_OUTPUTBYTES
) value indistinguishable from random data without knowing k
.
Optionally, a 16-bytes (crypto_core_hchacha20_CONSTBYTES
) constant c
can be specified to personalize the function to an application. c
can be left to NULL
in order to use the default constant.
The following code snippet case thus be used to construct a ChaCha20-Poly1305 variant with a 192-bits nonce (XChaCha20) on libsodium < 1.0.12 (versions >= 1.0.12 already include this construction).
Last updated