c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 1) // SPDX-License-Identifier: GPL-2.0
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 2) /*
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 3) * Implementation of HKDF ("HMAC-based Extract-and-Expand Key Derivation
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 4) * Function"), aka RFC 5869. See also the original paper (Krawczyk 2010):
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 5) * "Cryptographic Extraction and Key Derivation: The HKDF Scheme".
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 6) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 7) * This is used to derive keys from the fscrypt master keys.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 8) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 9) * Copyright 2019 Google LLC
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 10) */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 11)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 12) #include <crypto/hash.h>
a24d22b225ce1 (Eric Biggers 2020-11-12 21:20:21 -0800 13) #include <crypto/sha2.h>
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 14)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 15) #include "fscrypt_private.h"
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 16)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 17) /*
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 18) * HKDF supports any unkeyed cryptographic hash algorithm, but fscrypt uses
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 19) * SHA-512 because it is reasonably secure and efficient; and since it produces
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 20) * a 64-byte digest, deriving an AES-256-XTS key preserves all 64 bytes of
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 21) * entropy from the master key and requires only one iteration of HKDF-Expand.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 22) */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 23) #define HKDF_HMAC_ALG "hmac(sha512)"
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 24) #define HKDF_HASHLEN SHA512_DIGEST_SIZE
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 25)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 26) /*
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 27) * HKDF consists of two steps:
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 28) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 29) * 1. HKDF-Extract: extract a pseudorandom key of length HKDF_HASHLEN bytes from
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 30) * the input keying material and optional salt.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 31) * 2. HKDF-Expand: expand the pseudorandom key into output keying material of
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 32) * any length, parameterized by an application-specific info string.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 33) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 34) * HKDF-Extract can be skipped if the input is already a pseudorandom key of
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 35) * length HKDF_HASHLEN bytes. However, cipher modes other than AES-256-XTS take
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 36) * shorter keys, and we don't want to force users of those modes to provide
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 37) * unnecessarily long master keys. Thus fscrypt still does HKDF-Extract. No
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 38) * salt is used, since fscrypt master keys should already be pseudorandom and
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 39) * there's no way to persist a random salt per master key from kernel mode.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 40) */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 41)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 42) /* HKDF-Extract (RFC 5869 section 2.2), unsalted */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 43) static int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm,
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 44) unsigned int ikmlen, u8 prk[HKDF_HASHLEN])
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 45) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 46) static const u8 default_salt[HKDF_HASHLEN];
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 47) int err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 48)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 49) err = crypto_shash_setkey(hmac_tfm, default_salt, HKDF_HASHLEN);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 50) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 51) return err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 52)
3e185a56eb696 (Eric Biggers 2020-05-01 22:31:15 -0700 53) return crypto_shash_tfm_digest(hmac_tfm, ikm, ikmlen, prk);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 54) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 55)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 56) /*
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 57) * Compute HKDF-Extract using the given master key as the input keying material,
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 58) * and prepare an HMAC transform object keyed by the resulting pseudorandom key.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 59) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 60) * Afterwards, the keyed HMAC transform object can be used for HKDF-Expand many
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 61) * times without having to recompute HKDF-Extract each time.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 62) */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 63) int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 64) unsigned int master_key_size)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 65) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 66) struct crypto_shash *hmac_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 67) u8 prk[HKDF_HASHLEN];
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 68) int err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 69)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 70) hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, 0);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 71) if (IS_ERR(hmac_tfm)) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 72) fscrypt_err(NULL, "Error allocating " HKDF_HMAC_ALG ": %ld",
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 73) PTR_ERR(hmac_tfm));
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 74) return PTR_ERR(hmac_tfm);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 75) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 76)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 77) if (WARN_ON(crypto_shash_digestsize(hmac_tfm) != sizeof(prk))) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 78) err = -EINVAL;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 79) goto err_free_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 80) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 81)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 82) err = hkdf_extract(hmac_tfm, master_key, master_key_size, prk);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 83) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 84) goto err_free_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 85)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 86) err = crypto_shash_setkey(hmac_tfm, prk, sizeof(prk));
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 87) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 88) goto err_free_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 89)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 90) hkdf->hmac_tfm = hmac_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 91) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 92)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 93) err_free_tfm:
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 94) crypto_free_shash(hmac_tfm);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 95) out:
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 96) memzero_explicit(prk, sizeof(prk));
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 97) return err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 98) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 99)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 100) /*
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 101) * HKDF-Expand (RFC 5869 section 2.3). This expands the pseudorandom key, which
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 102) * was already keyed into 'hkdf->hmac_tfm' by fscrypt_init_hkdf(), into 'okmlen'
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 103) * bytes of output keying material parameterized by the application-specific
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 104) * 'info' of length 'infolen' bytes, prefixed by "fscrypt\0" and the 'context'
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 105) * byte. This is thread-safe and may be called by multiple threads in parallel.
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 106) *
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 107) * ('context' isn't part of the HKDF specification; it's just a prefix fscrypt
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 108) * adds to its application-specific info strings to guarantee that it doesn't
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 109) * accidentally repeat an info string when using HKDF for different purposes.)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 110) */
2a5831b1d2975 (Eric Biggers 2019-12-09 12:40:54 -0800 111) int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 112) const u8 *info, unsigned int infolen,
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 113) u8 *okm, unsigned int okmlen)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 114) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 115) SHASH_DESC_ON_STACK(desc, hkdf->hmac_tfm);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 116) u8 prefix[9];
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 117) unsigned int i;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 118) int err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 119) const u8 *prev = NULL;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 120) u8 counter = 1;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 121) u8 tmp[HKDF_HASHLEN];
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 122)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 123) if (WARN_ON(okmlen > 255 * HKDF_HASHLEN))
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 124) return -EINVAL;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 125)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 126) desc->tfm = hkdf->hmac_tfm;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 127)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 128) memcpy(prefix, "fscrypt\0", 8);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 129) prefix[8] = context;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 130)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 131) for (i = 0; i < okmlen; i += HKDF_HASHLEN) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 132)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 133) err = crypto_shash_init(desc);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 134) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 135) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 136)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 137) if (prev) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 138) err = crypto_shash_update(desc, prev, HKDF_HASHLEN);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 139) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 140) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 141) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 142)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 143) err = crypto_shash_update(desc, prefix, sizeof(prefix));
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 144) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 145) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 146)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 147) err = crypto_shash_update(desc, info, infolen);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 148) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 149) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 150)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 151) BUILD_BUG_ON(sizeof(counter) != 1);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 152) if (okmlen - i < HKDF_HASHLEN) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 153) err = crypto_shash_finup(desc, &counter, 1, tmp);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 154) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 155) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 156) memcpy(&okm[i], tmp, okmlen - i);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 157) memzero_explicit(tmp, sizeof(tmp));
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 158) } else {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 159) err = crypto_shash_finup(desc, &counter, 1, &okm[i]);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 160) if (err)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 161) goto out;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 162) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 163) counter++;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 164) prev = &okm[i];
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 165) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 166) err = 0;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 167) out:
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 168) if (unlikely(err))
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 169) memzero_explicit(okm, okmlen); /* so caller doesn't need to */
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 170) shash_desc_zero(desc);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 171) return err;
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 172) }
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 173)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 174) void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf)
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 175) {
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 176) crypto_free_shash(hkdf->hmac_tfm);
c1144c9b8ad94 (Eric Biggers 2019-08-04 19:35:47 -0700 177) }