crypto: drbg - Remove support for "prediction resistance"
Subsystems (2)
PATCH 1/1 crypto: drbg - Remove support for "prediction resistance"
"Prediction resistance", i.e. the property that the RNG's output is unpredictable even after a state compromise, might sound like a nice property to have. In reality, it's not very practical, as it requires that fresh entropy be pulled on every request. (The normal Linux RNG doesn't provide prediction resistance.) In the case of drbg.c, that means pulling from "jitterentropy", which is extremely slow.
For some perspective, running a simple benchmark, generating 32 random bytes takes the following amount of time:
get_random_bytes(): 90 ns
drbg_nopr_hmac_sha512: 3707 ns
drbg_pr_hmac_sha512: 773082 nsSo at least in this case, the "pr" (prediction-resistant) DRBG is over 200 times slower than the "nopr" (non-prediction-resistant) DRBG, or over 8000 times slower than the normal Linux RNG. While anyone using drbg.c has always had to tolerate that it's slower than the normal Linux RNG, the "pr" DRBG is clearly at another level of slowness.
Thus, the following is also entirely unsurprising:
- FIPS 140-3 doesn't actually require that SP800-90A DRBG implementations support prediction resistance. The non-prediction resistant DRBGs can be, and have been, certified.
- drbg.c registers "drbg_nopr_hmac_sha512" with a higher cra_priority than "drbg_pr_hmac_sha512". So "drbg_nopr_hmac_sha512" is already the one actually being used in practice.
Given these considerations, it's clear that "drbg_pr_hmac_sha512" isn't actually useful, and it essentially just existed as another curiosity in the museum of crypto algorithms. Remove it to simplify the code.
--- crypto/drbg.c | 82 ++++++------------- crypto/testmgr.c | 21 +---- crypto/testmgr.h | 202 ----------------------------------------------- 3 files changed, 27 insertions(+), 278 deletions(-)
crypto/drbg.c +24 -58
@@ -1,9 +1,8 @@/* * DRBG: Deterministic Random Bits Generator -* Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A, -* both with and without prediction resistance +* Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A * * Copyright Stephan Mueller <[email protected]>, 2014 * Copyright 2026 Google LLC * * Redistribution and use in source and binary forms, with or without
@@ -129,11 +128,10 @@ struct drbg_state {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; -bool pr;/* Prediction resistance enabled? */ struct crypto_rng *jent;const u8 *test_entropy;size_t test_entropylen; };
@@ -368,13 +366,12 @@ static int drbg_generate(struct drbg_state *drbg, u8 *out, size_t outlen,* * 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->pr || drbg->reseed_ctr >DRBG_MAX_REQUESTS ) { -pr_devel ("DRBG: reseeding before generation (prediction resistance: %s)\n" , -str_true_false (drbg->pr)); +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 */
@@ -429,33 +426,31 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm,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,size_t pers_len,bool pr) +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 with prediction resistance %s\n" , -str_enabled_disabled (pr)); +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 caller can select prediction resistance -* all DRBG types support prediction resistance +* 9.1 step 2 is implicit, as this implementation doesn't support +* prediction resistance */ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - drbg->pr = pr;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 ) {
@@ -477,22 +472,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, } drbg->instantiated = true;return 0 ; } -static int drbg_kcapi_seed_pr (struct crypto_rng *tfm, -const u8 *seed,unsigned int slen) -{ -return drbg_kcapi_seed (tfm, seed, slen,/* pr= */ true); -} - -static int drbg_kcapi_seed_nopr (struct crypto_rng *tfm, -const u8 *seed,unsigned int slen) -{ -return drbg_kcapi_seed (tfm, seed, slen,/* pr= */ false); -} -/* * Generate random numbers invoked by the kernel crypto API: * * src is additional input supplied to the RNG. * slen is the length of src.
@@ -587,35 +570,21 @@ static inline int __init drbg_healthcheck_sanity(void)kfree (drbg);return 0 ; } -static struct rng_alg drbg_algs[] = { - { - .base.cra_name ="stdrng" , - .base.cra_driver_name ="drbg_pr_hmac_sha512" , - .base.cra_priority =200 , - .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_pr, - .generate = drbg_kcapi_generate, - .base.cra_exit = drbg_kcapi_exit, - }, - { - .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_nopr, - .generate = drbg_kcapi_generate, - .base.cra_exit = drbg_kcapi_exit, - }, +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;
@@ -623,29 +592,26 @@ static int __init drbg_init(void) ret =drbg_healthcheck_sanity ();if (ret)return ret;/* -* In FIPS mode, boost the algorithm priorities to ensure that when -* users request "stdrng", they really get an algorithm from here. +* In FIPS mode, boost the algorithm priority to ensure that when users +* request "stdrng", they really get the algorithm from here. */ -if (fips_enabled) { -for (size_t i =0 ; i <ARRAY_SIZE (drbg_algs); i++) - drbg_algs[i].base.cra_priority +=2000 ; - } +if (fips_enabled) + drbg_alg.base.cra_priority +=2000 ; -return crypto_register_rngs (drbg_algs,ARRAY_SIZE (drbg_algs)); +return crypto_register_rng (&drbg_alg); } static void __exit drbg_exit(void) { -crypto_unregister_rngs (drbg_algs,ARRAY_SIZE (drbg_algs)); +crypto_unregister_rng (&drbg_alg); }module_init (drbg_init);module_exit (drbg_exit);MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Stephan Mueller <[email protected]>" );MODULE_DESCRIPTION ("NIST SP800-90A Deterministic Random Bit Generator (DRBG)" );MODULE_ALIAS_CRYPTO ("stdrng" ); -MODULE_ALIAS_CRYPTO ("drbg_pr_hmac_sha512" );MODULE_ALIAS_CRYPTO ("drbg_nopr_hmac_sha512" );
crypto/testmgr.c +3 -18
@@ -3479,12 +3479,12 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver, desc->suite.comp.decomp.count);crypto_free_acomp (acomp);return err; } -static int drbg_cavs_test (const struct drbg_testvec *test,int pr, -const char *driver,u32 type,u32 mask) +static int drbg_cavs_test (const struct drbg_testvec *test,const char *driver, +u32 type,u32 mask) {int ret = -EAGAIN ;struct crypto_rng *drng;unsigned char *buf =kzalloc (test->expectedlen,GFP_KERNEL );
@@ -3517,22 +3517,18 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,printk (KERN_ERR "alg: drbg: Failed to reseed rng\n" ); goto outbuf; } } -if (pr) -crypto_rng_set_entropy (drng, test->entpra, test->entprlen); ret =crypto_rng_generate (drng, test->addtla, test->addtllen, buf, test->expectedlen);if (ret <0 ) {printk (KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n" , driver); goto outbuf; } -if (pr) -crypto_rng_set_entropy (drng, test->entprb, test->entprlen); ret =crypto_rng_generate (drng, test->addtlb, test->addtllen, buf, test->expectedlen);if (ret <0 ) {printk (KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n" , driver);
@@ -3550,20 +3546,16 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,static int alg_test_drbg (const struct alg_test_desc *desc,const char *driver,u32 type,u32 mask) {int err =0 ; -int pr =0 ;int i =0 ;const struct drbg_testvec *template = desc->suite.drbg.vecs;unsigned int tcount = desc->suite.drbg.count; -if (0 ==memcmp (driver,"drbg_pr_" ,8 )) - pr =1 ; -for (i =0 ; i < tcount; i++) { - err =drbg_cavs_test (&template[i], pr, driver, type, mask); + err =drbg_cavs_test (&template[i], driver, type, mask);if (err) {printk (KERN_ERR "alg: drbg: Test %d failed for %s\n" , i, driver); err = -EINVAL ;break ;
@@ -4654,17 +4646,10 @@ static const struct alg_test_desc alg_test_descs[] = { .test = alg_test_drbg, .fips_allowed = 1, .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_pr_hmac_sha512", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_hmac_sha512_tv_template) - } }, { .alg = "ecb(aes)", .generic_driver = "ecb(aes-lib)", .test = alg_test_skcipher, .fips_allowed = 1,
crypto/testmgr.h +0 -202
222 lines not on this page · raw message
base-commit: 5b03b1f97542c49a498dbb3b4c1fefb3aca60032
prerequisite-patch-id: a1deee4f4c866867dadd5eee0efe2b669ef2d650
Signature · 1 line
2.54.0
Herbert Xu
maintainerQuoted 34 lines · Eric Biggers
"Prediction resistance", i.e. the property that the RNG's output is unpredictable even after a state compromise, might sound like a nice property to have. In reality, it's not very practical, as it requires that fresh entropy be pulled on every request. (The normal Linux RNG doesn't provide prediction resistance.) In the case of
drbg.c, that means pulling from "jitterentropy", which is extremely slow.For some perspective, running a simple benchmark, generating 32 random bytes takes the following amount of time:
get_random_bytes(): 90 ns drbg_nopr_hmac_sha512: 3707 ns drbg_pr_hmac_sha512: 773082 nsSo at least in this case, the "pr" (prediction-resistant) DRBG is over 200 times slower than the "nopr" (non-prediction-resistant) DRBG, or over 8000 times slower than the normal Linux RNG. While anyone using
drbg.chas always had to tolerate that it's slower than the normal Linux RNG, the "pr" DRBG is clearly at another level of slowness.Thus, the following is also entirely unsurprising:
- FIPS 140-3 doesn't actually require that SP800-90A DRBG implementations support prediction resistance. The non-prediction resistant DRBGs can be, and have been, certified.
-
drbg.cregisters "drbg_nopr_hmac_sha512" with a highercra_prioritythan "drbg_pr_hmac_sha512". So "drbg_nopr_hmac_sha512" is already the one actually being used in practice.Given these considerations, it's clear that "
drbg_pr_hmac_sha512" isn't actually useful, and it essentially just existed as another curiosity in the museum of crypto algorithms. Remove it to simplify the code.
Quoted 7 lines
Suggested-by Joachim Vandersmissen <[email protected]>Signed-off-by Eric Biggers <[email protected]>--- crypto/drbg.c | 82 ++++++------------- crypto/testmgr.c | 21 +---- crypto/testmgr.h | 202 ----------------------------------------------- 3 files changed, 27 insertions(+), 278 deletions(-)
Patch applied. Thanks.
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt