diff options
| author | Eric Biggers <ebiggers@kernel.org> | 2026-04-19 23:34:06 -0700 |
|---|---|---|
| committer | Herbert Xu <herbert@gondor.apana.org.au> | 2026-05-07 16:10:00 +0800 |
| commit | 245c8d0d177f129d105f84331272494e2cd31f2a (patch) | |
| tree | ad63ba1a9e91a46092b651dcefe9def2ff509e77 | |
| parent | fcc62e0991ff0ceb7f53a93f4b12982b7d91d233 (diff) | |
| download | linux-next-history-245c8d0d177f129d105f84331272494e2cd31f2a.tar.gz | |
crypto: drbg - Use HMAC-SHA512 library API
Since the HMAC algorithm is now fixed at HMAC-SHA512, just use the
HMAC-SHA512 library API. This is simpler and more efficient.
Remove error-handling code that is no longer needed.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
| -rw-r--r-- | crypto/Kconfig | 3 | ||||
| -rw-r--r-- | crypto/drbg.c | 213 |
2 files changed, 41 insertions, 175 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 1abb3d3564582..608b2c739193f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1115,10 +1115,9 @@ menu "Random number generation" config CRYPTO_DRBG tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" - select CRYPTO_HMAC select CRYPTO_JITTERENTROPY + select CRYPTO_LIB_SHA512 select CRYPTO_RNG - select CRYPTO_SHA512 help DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) diff --git a/crypto/drbg.c b/crypto/drbg.c index e62bde7aab43f..4f326385cf367 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -4,6 +4,7 @@ * both with and without prediction resistance * * 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 @@ -90,7 +91,6 @@ #include <crypto/internal/drbg.h> #include <crypto/internal/rng.h> -#include <crypto/hash.h> #include <crypto/sha2.h> #include <linux/fips.h> #include <linux/kernel.h> @@ -143,12 +143,11 @@ enum drbg_seed_state { 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 */ u8 C[DRBG_STATE_LEN]; /* current key -- 10.1.2.1 1b */ /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; size_t reseed_threshold; - void *priv_data; /* Cipher handle */ - enum drbg_seed_state seeded; /* DRBG fully seeded? */ unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ @@ -186,94 +185,67 @@ static int drbg_uninstantiate(struct drbg_state *drbg); * HMAC DRBG functions ******************************************************************/ -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in); -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key); -static int drbg_init_hash_kernel(struct drbg_state *drbg); -static int drbg_fini_hash_kernel(struct drbg_state *drbg); - MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ -static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) +static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, + int reseed) { - int ret = -EFAULT; int i = 0; - struct drbg_string seed1, seed2, vdata; - LIST_HEAD(seedlist); - LIST_HEAD(vdatalist); + struct hmac_sha512_ctx hmac_ctx; if (!reseed) { /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ memset(drbg->V, 1, DRBG_STATE_LEN); - drbg_kcapi_hmacsetkey(drbg, drbg->C); + hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); } - drbg_string_fill(&seed1, drbg->V, DRBG_STATE_LEN); - list_add_tail(&seed1.list, &seedlist); - /* buffer of seed2 will be filled in for loop below with one byte */ - drbg_string_fill(&seed2, NULL, 1); - list_add_tail(&seed2.list, &seedlist); - /* input data of seed is allowed to be NULL at this point */ - if (seed) - list_splice_tail(seed, &seedlist); - - drbg_string_fill(&vdata, drbg->V, DRBG_STATE_LEN); - list_add_tail(&vdata.list, &vdatalist); for (i = 2; 0 < i; i--) { /* first round uses 0x0, second 0x1 */ unsigned char prefix = DRBG_PREFIX0; if (1 == i) prefix = DRBG_PREFIX1; /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ - seed2.buf = &prefix; - ret = drbg_kcapi_hash(drbg, drbg->C, &seedlist); - if (ret) - return ret; - drbg_kcapi_hmacsetkey(drbg, drbg->C); + hmac_sha512_init(&hmac_ctx, &drbg->key); + hmac_sha512_update(&hmac_ctx, drbg->V, DRBG_STATE_LEN); + hmac_sha512_update(&hmac_ctx, &prefix, 1); + if (seed) { + struct drbg_string *input; + + list_for_each_entry(input, seed, list) + hmac_sha512_update(&hmac_ctx, input->buf, + input->len); + } + hmac_sha512_final(&hmac_ctx, drbg->C); + hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); /* 10.1.2.2 step 2 and 5 -- HMAC for V */ - ret = drbg_kcapi_hash(drbg, drbg->V, &vdatalist); - if (ret) - return ret; + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); /* 10.1.2.2 step 3 */ if (!seed) - return ret; + break; } - - return 0; } /* generate function of HMAC DRBG as defined in 10.1.2.5 */ -static int drbg_hmac_generate(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen, - struct list_head *addtl) +static void drbg_hmac_generate(struct drbg_state *drbg, + unsigned char *buf, + unsigned int buflen, + struct list_head *addtl) { int len = 0; - int ret = 0; - struct drbg_string data; - LIST_HEAD(datalist); /* 10.1.2.5 step 2 */ - if (addtl && !list_empty(addtl)) { - ret = drbg_hmac_update(drbg, addtl, 1); - if (ret) - return ret; - } + if (addtl && !list_empty(addtl)) + drbg_hmac_update(drbg, addtl, 1); - drbg_string_fill(&data, drbg->V, DRBG_STATE_LEN); - list_add_tail(&data.list, &datalist); while (len < buflen) { unsigned int outlen = 0; + /* 10.1.2.5 step 4.1 */ - ret = drbg_kcapi_hash(drbg, drbg->V, &datalist); - if (ret) - return ret; + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); outlen = (DRBG_STATE_LEN < (buflen - len)) ? DRBG_STATE_LEN : (buflen - len); @@ -284,22 +256,15 @@ static int drbg_hmac_generate(struct drbg_state *drbg, /* 10.1.2.5 step 6 */ if (addtl && !list_empty(addtl)) - ret = drbg_hmac_update(drbg, addtl, 1); + drbg_hmac_update(drbg, addtl, 1); else - ret = drbg_hmac_update(drbg, NULL, 1); - if (ret) - return ret; - - return len; + drbg_hmac_update(drbg, NULL, 1); } -static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed, enum drbg_seed_state new_seed_state) +static inline void __drbg_seed(struct drbg_state *drbg, struct list_head *seed, + int reseed, enum drbg_seed_state new_seed_state) { - int ret = drbg_hmac_update(drbg, seed, reseed); - - if (ret) - return ret; + drbg_hmac_update(drbg, seed, reseed); drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; @@ -325,27 +290,23 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, drbg->reseed_threshold = DRBG_MAX_REQUESTS; break; } - - return ret; } -static int drbg_seed_from_random(struct drbg_state *drbg) +static void drbg_seed_from_random(struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) { struct drbg_string data; LIST_HEAD(seedlist); unsigned char entropy[DRBG_SEC_STRENGTH]; - int ret; drbg_string_fill(&data, entropy, DRBG_SEC_STRENGTH); list_add_tail(&data.list, &seedlist); get_random_bytes(entropy, DRBG_SEC_STRENGTH); - ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); + __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); memzero_explicit(entropy, DRBG_SEC_STRENGTH); - return ret; } static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) @@ -477,8 +438,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, memset(drbg->C, 0, DRBG_STATE_LEN); } - ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state); - + __drbg_seed(drbg, &seedlist, reseed, new_seed_state); + ret = 0; out: memzero_explicit(entropy, sizeof(entropy)); @@ -490,6 +451,7 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; + memzero_explicit(&drbg->key, sizeof(drbg->key)); memzero_explicit(drbg->V, sizeof(drbg->V)); memzero_explicit(drbg->C, sizeof(drbg->C)); drbg->reseed_ctr = 0; @@ -497,24 +459,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) } /* - * Allocate all sub-structures for a DRBG state. - * The DRBG state structure must already be allocated. - */ -static inline int drbg_alloc_state(struct drbg_state *drbg) -{ - int ret = -ENOMEM; - - ret = drbg_init_hash_kernel(drbg); - if (ret < 0) - goto err; - return 0; - -err: - drbg_dealloc_state(drbg); - return ret; -} - -/* * DRBG generate function as required by SP800-90A - this function * generates random numbers * @@ -590,20 +534,16 @@ static int drbg_generate(struct drbg_state *drbg, } else if (rng_is_initialized() && (drbg->seeded == DRBG_SEED_STATE_PARTIAL || drbg_nopr_reseed_interval_elapsed(drbg))) { - len = drbg_seed_from_random(drbg); - if (len) - goto err; + drbg_seed_from_random(drbg); } if (addtl && 0 < addtl->len) list_add_tail(&addtl->list, &addtllist); /* 9.3.1 step 8 and 10 */ - len = drbg_hmac_generate(drbg, buf, buflen, &addtllist); + drbg_hmac_generate(drbg, buf, buflen, &addtllist); /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; - if (0 >= len) - goto err; /* * Section 11.3.3 requires to re-perform self tests after some @@ -718,10 +658,6 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, drbg->last_seed_time = 0; drbg->reseed_threshold = DRBG_MAX_REQUESTS; - ret = drbg_alloc_state(drbg); - if (ret) - goto unlock; - ret = drbg_prepare_hrng(drbg); if (ret) goto free_everything; @@ -737,10 +673,6 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, mutex_unlock(&drbg->drbg_mutex); return ret; -unlock: - mutex_unlock(&drbg->drbg_mutex); - return ret; - free_everything: mutex_unlock(&drbg->drbg_mutex); drbg_uninstantiate(drbg); @@ -762,7 +694,6 @@ static int drbg_uninstantiate(struct drbg_state *drbg) crypto_free_rng(drbg->jent); drbg->jent = NULL; - drbg_fini_hash_kernel(drbg); drbg_dealloc_state(drbg); /* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0; @@ -786,70 +717,6 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, } /*************************************************************** - * Kernel crypto API cipher invocations requested by DRBG - ***************************************************************/ - -struct sdesc { - struct shash_desc shash; -}; - -static int drbg_init_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc; - struct crypto_shash *tfm; - - tfm = crypto_alloc_shash(drbg->core->backend_cra_name, 0, 0); - if (IS_ERR(tfm)) { - pr_info("DRBG: could not allocate digest TFM handle: %s\n", - drbg->core->backend_cra_name); - return PTR_ERR(tfm); - } - BUG_ON(DRBG_STATE_LEN != crypto_shash_digestsize(tfm)); - sdesc = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!sdesc) { - crypto_free_shash(tfm); - return -ENOMEM; - } - - sdesc->shash.tfm = tfm; - drbg->priv_data = sdesc; - - return 0; -} - -static int drbg_fini_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc = drbg->priv_data; - if (sdesc) { - crypto_free_shash(sdesc->shash.tfm); - kfree_sensitive(sdesc); - } - drbg->priv_data = NULL; - return 0; -} - -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key) -{ - struct sdesc *sdesc = drbg->priv_data; - - crypto_shash_setkey(sdesc->shash.tfm, key, DRBG_STATE_LEN); -} - -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in) -{ - struct sdesc *sdesc = drbg->priv_data; - struct drbg_string *input = NULL; - - crypto_shash_init(&sdesc->shash); - list_for_each_entry(input, in, list) - crypto_shash_update(&sdesc->shash, input->buf, input->len); - return crypto_shash_final(&sdesc->shash, outval); -} - -/*************************************************************** * Kernel crypto API interface to register DRBG ***************************************************************/ |
