diff options
Diffstat (limited to 'crypto/drbg.c')
| -rw-r--r-- | crypto/drbg.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/crypto/drbg.c b/crypto/drbg.c new file mode 100644 index 000000000..d66c7211d --- /dev/null +++ b/crypto/drbg.c @@ -0,0 +1,617 @@ +/* + * DRBG: Deterministic Random Bits Generator + * Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A + * + * Copyright Stephan Mueller <smueller@chronox.de>, 2014 + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * DRBG Usage + * ========== + * The SP 800-90A DRBG allows the user to specify a personalization string + * for initialization as well as an additional information string for each + * random number request. The following code fragments show how a caller + * uses the kernel crypto API to use the full functionality of the DRBG. + * + * Usage without any additional data + * --------------------------------- + * struct crypto_rng *drng; + * int err; + * char data[DATALEN]; + * + * drng = crypto_alloc_rng(drng_name, 0, 0); + * err = crypto_rng_get_bytes(drng, data, DATALEN); + * crypto_free_rng(drng); + * + * + * Usage with personalization string during initialization + * ------------------------------------------------------- + * struct crypto_rng *drng; + * int err; + * char data[DATALEN]; + * char personalization[11] = "some-string"; + * + * drng = crypto_alloc_rng(drng_name, 0, 0); + * // The reset completely re-initializes the DRBG with the provided + * // personalization string + * err = crypto_rng_reset(drng, personalization, strlen(personalization)); + * err = crypto_rng_get_bytes(drng, data, DATALEN); + * crypto_free_rng(drng); + * + * + * Usage with additional information string during random number request + * --------------------------------------------------------------------- + * struct crypto_rng *drng; + * int err; + * char data[DATALEN]; + * char addtl_string[11] = "some-string"; + * + * drng = crypto_alloc_rng(drng_name, 0, 0); + * err = crypto_rng_generate(drng, addtl_string, strlen(addtl_string), + data, DATALEN); + * crypto_free_rng(drng); + * + * + * Usage with personalization and additional information strings + * ------------------------------------------------------------- + * Just mix both scenarios above. + */ + +#include <crypto/internal/rng.h> +#include <crypto/sha2.h> +#include <linux/fips.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/string_choices.h> +#include <linux/unaligned.h> + +/* State length in bytes */ +#define DRBG_STATE_LEN SHA512_DIGEST_SIZE + +/* Security strength in bytes */ +#define DRBG_SEC_STRENGTH (SHA512_DIGEST_SIZE / 2) + +/* + * Maximum number of requests before reseeding is forced. + * SP800-90A allows this to be up to 2**48. We use a lower value. + */ +#define DRBG_MAX_REQUESTS 4096 + +/* + * Maximum number of random bytes that can be requested at once. + * SP800-90A allows up to 2**19 bits, which is 2**16 bytes. + */ +#define DRBG_MAX_REQUEST_BYTES (1 << 16) + +/* + * Maximum length of additional info and personalization strings, in bytes. + * SP800-90A allows up to 2**35 bits, i.e. 2**32 bytes. We use 2**32 - 2 bytes + * so that the value never quite completely fills the range of a size_t, + * allowing the health check to verify that larger values are rejected. + */ +#define DRBG_MAX_ADDTL_BYTES (U32_MAX - 1) + +struct drbg_state { + struct mutex drbg_mutex; /* lock around DRBG */ + u8 V[DRBG_STATE_LEN]; /* internal state -- 10.1.2.1 1a */ + struct hmac_sha512_key key; /* current key -- 10.1.2.1 1b */ + /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ + size_t reseed_ctr; + bool instantiated; + struct crypto_rng *jent; + const u8 *test_entropy; + size_t test_entropylen; +}; + +/****************************************************************** + * HMAC DRBG functions + ******************************************************************/ + +/* update function of HMAC DRBG as defined in 10.1.2.2 */ +static void drbg_hmac_update(struct drbg_state *drbg, + const u8 *data1, size_t data1_len, + const u8 *data2, size_t data2_len) +{ + struct hmac_sha512_ctx hmac_ctx; + u8 new_key[DRBG_STATE_LEN]; + + for (u8 i = 0; i < 2; i++) { + /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ + hmac_sha512_init(&hmac_ctx, &drbg->key); + hmac_sha512_update(&hmac_ctx, drbg->V, DRBG_STATE_LEN); + hmac_sha512_update(&hmac_ctx, &i, 1); + hmac_sha512_update(&hmac_ctx, data1, data1_len); + hmac_sha512_update(&hmac_ctx, data2, data2_len); + hmac_sha512_final(&hmac_ctx, new_key); + hmac_sha512_preparekey(&drbg->key, new_key, DRBG_STATE_LEN); + + /* 10.1.2.2 step 2 and 5 -- HMAC for V */ + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); + + /* 10.1.2.2 step 3 */ + if (data1_len == 0 && data2_len == 0) + break; + } + memzero_explicit(new_key, sizeof(new_key)); +} + +/* generate function of HMAC DRBG as defined in 10.1.2.5 */ +static void drbg_hmac_generate(struct drbg_state *drbg, u8 *out, size_t outlen, + const u8 *addtl1, size_t addtl1_len) +{ + u8 addtl2[32]; + size_t addtl2_len = 0; + + /* + * Append some bytes from get_random_bytes() to the additional input + * string, except when in test mode (as it would break the tests). + * Using a nonempty additional input string works around the forward + * secrecy bug in HMAC_DRBG described by Woodage & Shumow (2018) + * (https://eprint.iacr.org/2018/349.pdf). Filling the string with + * get_random_bytes() rather than a fixed value is safer still, and in + * particular makes random.c reseeds be immediately reflected. + * + * Note that there's no need to pull bytes from jitterentropy here too, + * since FIPS doesn't require any entropy in the additional input. + */ + if (drbg->test_entropylen == 0) { + get_random_bytes(addtl2, sizeof(addtl2)); + addtl2_len = sizeof(addtl2); + } + + /* 10.1.2.5 step 2 */ + if (addtl1_len || addtl2_len) + drbg_hmac_update(drbg, addtl1, addtl1_len, addtl2, addtl2_len); + + while (outlen) { + size_t n = min(DRBG_STATE_LEN, outlen); + + /* 10.1.2.5 step 4.1 */ + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); + + /* 10.1.2.5 step 4.2 */ + memcpy(out, drbg->V, n); + out += n; + outlen -= n; + } + + /* 10.1.2.5 step 6 */ + drbg_hmac_update(drbg, addtl1, addtl1_len, addtl2, addtl2_len); + + memzero_explicit(addtl2, sizeof(addtl2)); +} + +/* + * Seeding or reseeding of the DRBG + * + * @drbg: DRBG state struct + * @pers: personalization / additional information buffer + * @pers_len: length of @pers in bytes + * @reseed: false for initial seeding (instantiation), true for reseeding + * + * return: + * 0 on success + * error value otherwise + */ +static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, + bool reseed) + __must_hold(&drbg->drbg_mutex) +{ + int ret; + u8 entropy_buf[(32 + 16) * 2]; + size_t entropylen; + const u8 *entropy; + + /* 9.1 / 9.2 / 9.3.1 step 3 */ + if (pers_len > DRBG_MAX_ADDTL_BYTES) { + pr_devel("DRBG: personalization string too long %zu\n", + pers_len); + return -EINVAL; + } + + if (drbg->test_entropylen) { + entropy = drbg->test_entropy; + entropylen = drbg->test_entropylen; + pr_devel("DRBG: using test entropy\n"); + } else { + /* + * Gather entropy equal to the security strength of the DRBG. + * With a derivation function, a nonce is required in addition + * to the entropy. A nonce must be at least 1/2 of the security + * strength of the DRBG in size. Thus, entropy + nonce is 3/2 + * of the strength. The consideration of a nonce is only + * applicable during initial seeding. + */ + entropy = entropy_buf; + if (!reseed) + entropylen = ((DRBG_SEC_STRENGTH + 1) / 2) * 3; + else + entropylen = DRBG_SEC_STRENGTH; + BUG_ON(entropylen * 2 > sizeof(entropy_buf)); + + /* Get seed from in-kernel /dev/urandom */ + get_random_bytes(entropy_buf, entropylen); + + if (!drbg->jent) { + pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n", + entropylen); + } else { + /* + * Get seed from Jitter RNG, failures are + * fatal only in FIPS mode. + */ + ret = crypto_rng_get_bytes(drbg->jent, + &entropy_buf[entropylen], + entropylen); + if (fips_enabled && ret) { + pr_devel("DRBG: jent failed with %d\n", ret); + + /* + * Do not treat the transient failure of the + * Jitter RNG as an error that needs to be + * reported. The combined number of the + * maximum reseed threshold times the maximum + * number of Jitter RNG transient errors is + * less than the reseed threshold required by + * SP800-90A allowing us to treat the + * transient errors as such. + * + * However, we mandate that at least the first + * seeding operation must succeed with the + * Jitter RNG. + */ + if (!reseed || ret != -EAGAIN) + goto out; + } + + entropylen *= 2; + pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n", + entropylen); + } + } + + if (pers_len) + pr_devel("DRBG: using personalization string\n"); + + drbg_hmac_update(drbg, entropy, entropylen, pers, pers_len); + drbg->reseed_ctr = 1; + ret = 0; +out: + memzero_explicit(entropy_buf, sizeof(entropy_buf)); + + return ret; +} + +/* + * Generate random bytes from an SP800-90A DRBG. + * + * @drbg DRBG state handle + * @out Buffer where to store the random bytes + * @outlen Number of random bytes to generate + * @addtl Optional additional input that is mixed into state + * @addtl_len Length of @addtl in bytes, may be 0 + * + * return: 0 when all bytes are generated; < 0 in case of an error + */ +static int drbg_generate(struct drbg_state *drbg, u8 *out, size_t outlen, + const u8 *addtl, size_t addtl_len) + __must_hold(&drbg->drbg_mutex) +{ + int err; + + if (!drbg->instantiated) { + pr_devel("DRBG: not yet instantiated\n"); + return -EINVAL; + } + if (out == NULL || outlen == 0) { + pr_devel("DRBG: no output buffer provided\n"); + return -EINVAL; + } + if (addtl == NULL && addtl_len != 0) { + pr_devel("DRBG: wrong format of additional information\n"); + return -EINVAL; + } + + /* 9.3.1 step 2 */ + if (outlen > DRBG_MAX_REQUEST_BYTES) { + pr_devel("DRBG: request length is too long %zu\n", outlen); + return -EINVAL; + } + + /* 9.3.1 step 3 is implicit with the chosen DRBG */ + + /* 9.3.1 step 4 */ + if (addtl_len > DRBG_MAX_ADDTL_BYTES) { + pr_devel("DRBG: additional information string too long %zu\n", + addtl_len); + return -EINVAL; + } + /* 9.3.1 step 5 is implicit with the chosen DRBG */ + + /* + * 9.3.1 step 6 and 9 supplemented by 9.3.2 step c is implemented + * here. The spec is a bit convoluted here, we make it simpler. + * + * We no longer try to detect when random.c has reseeded itself and call + * drbg_seed() then too, since drbg_hmac_generate() adds bytes from + * random.c to the additional input, which is a de facto reseed anyway. + */ + if (drbg->reseed_ctr > DRBG_MAX_REQUESTS) { + pr_devel("DRBG: reseeding before generation\n"); + /* 9.3.1 steps 7.1 through 7.3 */ + err = drbg_seed(drbg, addtl, addtl_len, true); + if (err) + return err; + /* 9.3.1 step 7.4 */ + addtl = NULL; + addtl_len = 0; + } + + /* 9.3.1 step 8 and 10 */ + drbg_hmac_generate(drbg, out, outlen, addtl, addtl_len); + + /* 10.1.2.5 step 7 */ + drbg->reseed_ctr++; + + /* + * Section 11.3.3 requires to re-perform self tests after some + * generated random numbers. The chosen value after which self + * test is performed is arbitrary, but it should be reasonable. + * However, we do not perform the self tests because of the following + * reasons: it is mathematically impossible that the initial self tests + * were successfully and the following are not. If the initial would + * pass and the following would not, the kernel integrity is violated. + * In this case, the entire kernel operation is questionable and it + * is unlikely that the integrity violation only affects the + * correct operation of the DRBG. + */ + + return 0; +} + +/*************************************************************** + * Kernel crypto API interface to DRBG + ***************************************************************/ + +static int drbg_kcapi_init(struct crypto_tfm *tfm) +{ + struct drbg_state *drbg = crypto_tfm_ctx(tfm); + + mutex_init(&drbg->drbg_mutex); + + return 0; +} + +/* Set test entropy in the DRBG. */ +static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, + const u8 *data, unsigned int len) +{ + struct drbg_state *drbg = crypto_rng_ctx(tfm); + + mutex_lock(&drbg->drbg_mutex); + drbg->test_entropy = data; + drbg->test_entropylen = len; + mutex_unlock(&drbg->drbg_mutex); +} + +/* Seed (i.e. instantiate) or re-seed the DRBG. */ +static int drbg_kcapi_seed(struct crypto_rng *tfm, + const u8 *pers, unsigned int pers_len) +{ + static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ + struct drbg_state *drbg = crypto_rng_ctx(tfm); + int ret; + + pr_devel("DRBG: Initializing DRBG\n"); + guard(mutex)(&drbg->drbg_mutex); + + if (drbg->instantiated) + return drbg_seed(drbg, pers, pers_len, /* reseed= */ true); + + /* 9.1 step 1 is implicit with the selected DRBG type */ + + /* + * 9.1 step 2 is implicit, as this implementation doesn't support + * prediction resistance + */ + + /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ + + memset(drbg->V, 1, DRBG_STATE_LEN); + hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); + + /* Allocate jitterentropy_rng if not in test mode. */ + if (drbg->test_entropylen == 0) { + drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); + if (IS_ERR(drbg->jent)) { + ret = PTR_ERR(drbg->jent); + drbg->jent = NULL; + if (fips_enabled) + return ret; + pr_info("DRBG: Continuing without Jitter RNG\n"); + } + } + + ret = drbg_seed(drbg, pers, pers_len, /* reseed= */ false); + if (ret) { + crypto_free_rng(drbg->jent); + drbg->jent = NULL; + return ret; + } + drbg->instantiated = true; + return 0; +} + +/* + * Generate random numbers invoked by the kernel crypto API: + * + * src is additional input supplied to the RNG. + * slen is the length of src. + * dst is the output buffer where random data is to be stored. + * dlen is the length of dst. + */ +static int drbg_kcapi_generate(struct crypto_rng *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int dlen) +{ + struct drbg_state *drbg = crypto_rng_ctx(tfm); + + /* + * Break the request into multiple requests if needed, to avoid + * exceeding the maximum request length of the core algorithm. + */ + do { + unsigned int n = min(dlen, DRBG_MAX_REQUEST_BYTES); + int err; + + mutex_lock(&drbg->drbg_mutex); + err = drbg_generate(drbg, dst, n, src, slen); + mutex_unlock(&drbg->drbg_mutex); + if (err < 0) + return err; + dst += n; + dlen -= n; + } while (dlen); + return 0; +} + +/* Uninstantiate the DRBG. */ +static void drbg_kcapi_exit(struct crypto_tfm *tfm) +{ + struct drbg_state *drbg = crypto_tfm_ctx(tfm); + + crypto_free_rng(drbg->jent); + memzero_explicit(drbg, sizeof(*drbg)); +} + +/* + * Tests as defined in 11.3.2 in addition to the cipher tests: testing + * of the error handling. + * + * Note: testing of failing seed source as defined in 11.3.2 is not applicable + * as seed source of get_random_bytes does not fail. + * + * Note 2: There is no sensible way of testing the reseed counter + * enforcement, so skip it. + */ +static inline int __init drbg_healthcheck_sanity(void) +{ +#define OUTBUFLEN 16 + u8 buf[OUTBUFLEN]; + struct drbg_state *drbg = NULL; + int ret; + + /* only perform test in FIPS mode */ + if (!fips_enabled) + return 0; + + drbg = kzalloc_obj(struct drbg_state); + if (!drbg) + return -ENOMEM; + + guard(mutex_init)(&drbg->drbg_mutex); + drbg->instantiated = true; + + /* + * if the following tests fail, it is likely that there is a buffer + * overflow as buf is much smaller than the requested or provided + * string lengths -- in case the error handling does not succeed + * we may get an OOPS. And we want to get an OOPS as this is a + * grave bug. + */ + + /* overflow addtllen with additional info string */ + ret = drbg_generate(drbg, buf, OUTBUFLEN, buf, + DRBG_MAX_ADDTL_BYTES + 1); + BUG_ON(ret == 0); + /* overflow max_bits */ + ret = drbg_generate(drbg, buf, DRBG_MAX_REQUEST_BYTES + 1, NULL, 0); + BUG_ON(ret == 0); + + /* overflow max addtllen with personalization string */ + ret = drbg_seed(drbg, buf, DRBG_MAX_ADDTL_BYTES + 1, false); + BUG_ON(ret == 0); + /* all tests passed */ + + pr_devel("DRBG: Sanity tests for failure code paths successfully " + "completed\n"); + + kfree(drbg); + return 0; +} + +static struct rng_alg drbg_alg = { + .base.cra_name = "stdrng", + .base.cra_driver_name = "drbg_nopr_hmac_sha512", + .base.cra_priority = 201, + .base.cra_ctxsize = sizeof(struct drbg_state), + .base.cra_module = THIS_MODULE, + .base.cra_init = drbg_kcapi_init, + .set_ent = drbg_kcapi_set_entropy, + .seed = drbg_kcapi_seed, + .generate = drbg_kcapi_generate, + .base.cra_exit = drbg_kcapi_exit, +}; + +static int __init drbg_init(void) +{ + int ret; + + ret = drbg_healthcheck_sanity(); + if (ret) + return ret; + + /* + * In FIPS mode, boost the algorithm priority to ensure that when users + * request "stdrng", they really get the algorithm from here. + */ + if (fips_enabled) + drbg_alg.base.cra_priority += 2000; + + return crypto_register_rng(&drbg_alg); +} + +static void __exit drbg_exit(void) +{ + crypto_unregister_rng(&drbg_alg); +} + +module_init(drbg_init); +module_exit(drbg_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); +MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG)"); +MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); |
