Fix and simplify the NIST DRBG implementation
Subsystems (7)
cover Fix and simplify the NIST DRBG implementation
This series is intended to be taken through the cryptodev tree. It can also be retrieved from:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git drbg-v1
This series fixes and greatly simplifies crypto/drbg.c, i.e. the kernel's implementation of NIST SP800-90A. This code isn't normally used, but it's sometimes used by people doing FIPS 140-3 certifications.
Note: this series is *not* meant to encourage using this code over random.c. In fact, my recent commit 65b3c2f627851639 made "normal" systems stop using this code. It's just that the reality is that this is in the kernel tree, it's been there for many years, and people are using it to get FIPS 140-3 certifications. As long as that's the case, it might as well be fixed up and simplified. Another reason to simplify this as much as possible is that for historical reasons it's accessible to unprivileged users via AF_ALG (even though it shouldn't be). So I do think this is a clear step forwards, regardless of level of enthusiasm for FIPS, especially considering the massively negative diffstat.
Patches 1-5 begin with some bug fixes. Fixes for CTR_DRBG and HASH_DRBG are included, despite that code being removed later in the series, so that they can be backported (though that is likely unused code anyway).
Patches 6-11 do some initial cleanups.
Patches 12-17 clean up the museum of DRBG variants to just support the HMAC-SHA512 DRBG only, dropping support for the others. This is already the default variant, it makes sense that it's the default, and it's probably the only one actually being used on current kernels. In any case, supporting more than one is pretty pointless. See the patches for more details about why it makes sense to keep using this one.
Patches 18-33 contain many more cleanups, including switching from the crypto_shash API to the crypto library.
Patch 34 is a significant one: it starts adding 32 bytes from get_random_bytes() to every additional input string. This is to work around the forward secrecy bug described in Woodage & Shumow (2018)
(https://eprint.iacr.org/2018/349.pdf), and to ensure that random.c reseeds are actually reflected in drbg.c. Of course, for FIPS 140-3 this is irrelevant, but this is the right thing to do in practice, and it should make drbg.c quite a bit more robust in practice. (This isn't particularly novel, either; BoringSSL does essentially this same thing.)
Patches 35-38 are some further cleanups, including some tweaks to when the formal reseeding happens.
Note: while the primary goal of this series is to fix and simplify this code, this series is also intended to preserve the FIPS 140-3 "certifiable" property of crypto/drbg.c. I.e. after this series, it should still be possible to get a FIPS 140-3 certification that covers it. In fact it should become quite a bit easier, since there will be only one DRBG variant to worry about and the code will be much more straightforward. If there's anything I missed, let me know.
Eric Biggers (38):
crypto: drbg - Fix returning success on failure in CTR_DRBG
crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG
crypto: drbg - Fix ineffective sanity check
crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels
crypto: drbg - Fix the fips_enabled priority boost
crypto: drbg - Remove always-enabled symbol CRYPTO_DRBG_HMAC
crypto: drbg - Remove broken commented-out code
crypto: drbg - Remove unhelpful helper functions
crypto: drbg - Remove obsolete FIPS 140-2 continuous test
crypto: drbg - Fold include/crypto/drbg.h into crypto/drbg.c
crypto: drbg - Remove import of crypto_cipher functions
crypto: drbg - Remove support for CTR_DRBG
crypto: drbg - Remove support for HASH_DRBG
crypto: drbg - Flatten the DRBG menu
crypto: testmgr - Add test for drbg_pr_hmac_sha512
crypto: testmgr - Update test for drbg_nopr_hmac_sha512
crypto: drbg - Remove support for HMAC-SHA256 and HMAC-SHA384
crypto: drbg - Simplify algorithm registration
crypto: drbg - De-virtualize drbg_state_ops
crypto: drbg - Move fixed values into constants
crypto: drbg - Embed V and C into struct drbg_state
crypto: drbg - Use HMAC-SHA512 library API
crypto: drbg - Remove drbg_core
crypto: drbg - Install separate seed functions for pr and nopr
crypto: drbg - Move module aliases to end of file
crypto: drbg - Consolidate "instantiate" logic and remove
drbg_state::C
crypto: drbg - Eliminate use of 'drbg_string' and lists
crypto: drbg - Simplify drbg_generate_long() and fold into caller
crypto: drbg - Put rng_alg methods in logical order
crypto: drbg - Fold drbg_instantiate() into drbg_kcapi_seed()
crypto: drbg - Separate "reseed" case in drbg_kcapi_seed()
crypto: drbg - Fold drbg_prepare_hrng() into drbg_kcapi_seed()
crypto: drbg - Simplify "uninstantiate" logic
crypto: drbg - Include get_random_bytes() output in additional input
crypto: drbg - Change DRBG_MAX_REQUESTS to 4096
crypto: drbg - Remove redundant reseeding based on random.c state
crypto: drbg - Clean up generation code
crypto: drbg - Clean up loop in drbg_hmac_update()
Documentation/crypto/api-samples.rst | 2 +- Documentation/crypto/userspace-if.rst | 2 +- arch/m68k/configs/amiga_defconfig | 2 - arch/m68k/configs/apollo_defconfig | 2 - arch/m68k/configs/atari_defconfig | 2 - arch/m68k/configs/bvme6000_defconfig | 2 - arch/m68k/configs/hp300_defconfig | 2 - arch/m68k/configs/mac_defconfig | 2 - arch/m68k/configs/multi_defconfig | 2 - arch/m68k/configs/mvme147_defconfig | 2 - arch/m68k/configs/mvme16x_defconfig | 2 - arch/m68k/configs/q40_defconfig | 2 - arch/m68k/configs/sun3_defconfig | 2 - arch/m68k/configs/sun3x_defconfig | 2 - arch/mips/configs/decstation_64_defconfig | 2 - arch/mips/configs/decstation_defconfig | 2 - arch/mips/configs/decstation_r4k_defconfig | 2 - crypto/Kconfig | 40 +- crypto/df_sp80090a.c | 8 +- crypto/drbg.c | 1800 +++-------------- crypto/testmgr.c | 143 +- crypto/testmgr.h | 1262 ++++-------- drivers/crypto/xilinx/xilinx-trng.c | 1 - include/crypto/df_sp80090a.h | 25 + include/crypto/drbg.h | 263 --- include/crypto/internal/drbg.h | 54 - .../crypto/chacha20-s390/test-cipher.c | 1 - 27 files changed, 728 insertions(+), 2903 deletions(-) delete mode 100644 include/crypto/drbg.h delete mode 100644 include/crypto/internal/drbg.h
base-commit: c1f49dea2b8f335813d3b348fd39117fb8efb428
Signature · 1 line
2.53.0
PATCH 1/38 crypto: drbg - Fix returning success on failure in CTR_DRBG
drbg_ctr_generate() sometimes returns success when it fails, leaving the output buffer uninitialized. Fix it.
--- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/drbg.c +1 -1
@@ -375,11 +375,11 @@ static int drbg_ctr_generate(struct drbg_state *drbg,/* 10.2.1.5.2 step 2 */ if (addtl && !list_empty (addtl)) { ret =drbg_ctr_update (drbg, addtl,2 );if (ret) -return 0 ; +return ret; }/* 10.2.1.5.2 step 4.1 */ ret =drbg_kcapi_sym_ctr (drbg,NULL ,0 , buf, len);if (ret)
base-commit: c1f49dea2b8f335813d3b348fd39117fb8efb428
Signature · 1 line
2.53.0
PATCH 2/38 crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG
In reply to Eric Biggersdrbg_cpu_to_be32() is being used to do a plain write to a byte array, which doesn't have any alignment guarantee. This can cause a misaligned write. Replace it with the correct function, put_unaligned_be32().
--- crypto/df_sp80090a.c | 7 ++++--- crypto/drbg.c | 3 ++- include/crypto/internal/drbg.h | 18 ------------------ 3 files changed, 6 insertions(+), 22 deletions(-)
crypto/df_sp80090a.c +4 -3
@@ -8,10 +8,11 @@#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> +#include <linux/unaligned.h> #include <crypto/aes.h> #include <crypto/df_sp80090a.h> #include <crypto/internal/drbg.h> static void drbg_kcapi_sym(struct aes_enckey *aeskey, unsigned char *outval,
@@ -139,14 +140,14 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey,return -EINVAL ;/* 10.4.2 step 2 -- calculate the entire length of all input data */ list_for_each_entry (seed, seedlist, list) inputlen += seed->len; -drbg_cpu_to_be32 (inputlen, &L_N [0 ]); +put_unaligned_be32 (inputlen, &L_N [0 ]);/* 10.4.2 step 3 */ -drbg_cpu_to_be32 (bytes_to_return, &L_N [4 ]); +put_unaligned_be32 (bytes_to_return, &L_N [4 ]);/* 10.4.2 step 5: length is L_N, input_string, one byte, padding */ padlen = (inputlen +sizeof (L_N ) +1 ) % (blocklen_bytes);/* wrap the padlen appropriately */ if (padlen)
@@ -173,11 +174,11 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey,/* * 10.4.2 step 9.1 - the padding is implicit as the buffer * holds zeros after allocation -- even the increment of i * is irrelevant as the increment remains within length of i */ -drbg_cpu_to_be32 (i, iv); +put_unaligned_be32 (i, iv);/* 10.4.2 step 9.2 -- BCC and concatenation with temp */ drbg_ctr_bcc (aeskey, temp + templen,K , &bcc_list, blocklen_bytes, keylen);/* 10.4.2 step 9.3 */ i++;
crypto/drbg.c +2 -1
@@ -101,10 +101,11 @@#include <crypto/df_sp80090a.h> #include <crypto/internal/cipher.h> #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/string_choices.h> +#include <linux/unaligned.h> /*************************************************************** * Backend cipher definitions available to DRBG ***************************************************************/
@@ -599,11 +600,11 @@ static int drbg_hash_df(struct drbg_state *drbg,unsigned char *tmp = drbg->scratchpad +drbg_statelen (drbg);struct drbg_string data;/* 10.4.1 step 3 */ input[0 ] =1 ; -drbg_cpu_to_be32 ((outlen *8 ), &input[1 ]); +put_unaligned_be32 (outlen *8 , &input[1 ]);/* 10.4.1 step 4.1 -- concatenation of data for input into hash */ drbg_string_fill (&data, input,5 );list_add (&data.list, entropylist);
include/crypto/internal/drbg.h +0 -18
@@ -7,28 +7,10 @@*/ #ifndef _INTERNAL_DRBG_H#define _INTERNAL_DRBG_H -/* -* Convert an integer into a byte representation of this integer. -* The byte representation is big-endian -* -* @val value to be converted -* @buf buffer holding the converted integer -- caller must ensure that -* buffer size is at least 32 bit -*/ -static inline void drbg_cpu_to_be32 (__u32 val,unsigned char *buf) -{ -struct s { -__be32 conv; - }; -struct s *conversion = (struct s *)buf; - - conversion->conv =cpu_to_be32 (val); -} -/* * Concatenation Helper and string operation helper * * SP800-90A requires the concatenation of different data. To avoid copying * buffers around or allocate additional memory, the following data structure
Signature · 1 line
2.53.0
PATCH 3/38 crypto: drbg - Fix ineffective sanity check
In reply to Eric BiggersFix drbg_healthcheck_sanity() to correctly check the return value of drbg_generate(). drbg_generate() returns 0 on success, or a negative errno value on failure. drbg_healthcheck_sanity() incorrectly assumed that it returned a positive value on success.
This didn't make the sanity check fail, but it made it ineffective.
--- crypto/drbg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
crypto/drbg.c +4 -5
@@ -1735,11 +1735,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,* Note 2: There is no sensible way of testing the reseed counter * enforcement, so skip it. */ static inline int __init drbg_healthcheck_sanity (void ) { -int len =0 ;#define OUTBUFLEN 16unsigned char buf[OUTBUFLEN ];struct drbg_state *drbg =NULL ;int ret;int rc = -EFAULT ;
@@ -1780,15 +1779,15 @@ static inline int __init drbg_healthcheck_sanity(void) max_addtllen =drbg_max_addtl (drbg); max_request_bytes =drbg_max_request_bytes (drbg);drbg_string_fill (&addtl, buf, max_addtllen +1 );/* overflow addtllen with additional info string */ - len =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); -BUG_ON (0 < len); + ret =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); +BUG_ON (ret ==0 );/* overflow max_bits */ - len =drbg_generate (drbg, buf, (max_request_bytes +1 ),NULL ); -BUG_ON (0 < len); + ret =drbg_generate (drbg, buf, max_request_bytes +1 ,NULL ); +BUG_ON (ret ==0 );/* overflow max addtllen with personalization string */ ret =drbg_seed (drbg, &addtl, false);BUG_ON (0 == ret);/* all tests passed */
Signature · 1 line
2.53.0
PATCH 4/38 crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels
In reply to Eric BiggersOn 64-bit kernels, drbg_max_addtl() returns 2**35 bytes. That's too large, for two reasons:
1. SP800-90A says the maximum limit is 2**35 *bits*, not 2**35 bytes. So the implemented limit has confused bits and bytes.
2. When drbg_kcapi_hash() calls crypto_shash_update() on the additional information string, the length is implicitly cast to 'unsigned int'. That truncates the additional information string to U32_MAX bytes.
Fix the maximum additional information string length to always be U32_MAX - 1, causing an error to be returned for any longer lengths.
--- include/crypto/drbg.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
include/crypto/drbg.h +7 -11
@@ -146,23 +146,19 @@ static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) {/* SP800-90A requires the limit 2**19 bits, but we return bytes */ return (1 <<16 ); } +/* +* SP800-90A allows implementations to support additional info / personalization +* strings of up to 2**35 bits. Implementations can have a smaller maximum. We +* use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a +* size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. +*/ static inline size_t drbg_max_addtl (struct drbg_state *drbg) { -/* SP800-90A requires 2**35 bytes additional info str / pers str */ -#if (__BITS_PER_LONG ==32 ) -/* -* SP800-90A allows smaller maximum numbers to be returned -- we -* return SIZE_MAX - 1 to allow the verification of the enforcement -* of this value in drbg_healthcheck_sanity. -*/ -return (SIZE_MAX -1 ); -#else -return (1UL <<35 ); -#endif +return U32_MAX -1 ; }static inline size_t drbg_max_requests (struct drbg_state *drbg) {/* SP800-90A requires 2**48 maximum requests before reseeding */
Signature · 1 line
2.53.0
PATCH 5/38 crypto: drbg - Fix the fips_enabled priority boost
In reply to Eric BiggersWhen fips_enabled=1, it seems to have been intended for one of the algorithms defined in crypto/drbg.c to be the highest priority "stdrng" algorithm, so that it is what is used by "stdrng" users.
However, the code only boosts the priority to 400, which is less than the priority 500 used in drivers/crypto/caam/caamprng.c. Thus, the CAAM RNG could be used instead.
Fix this by boosting the priority by 2000 instead of 200.
--- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/drbg.c +1 -1
@@ -1830,11 +1830,11 @@ static inline void __init drbg_fill_array(struct rng_alg *alg,* If FIPS mode enabled, the selected DRBG shall have the * highest cra_priority over other stdrng instances to ensure * it is selected. */ if (fips_enabled) - alg->base.cra_priority +=200 ; + alg->base.cra_priority +=2000 ; alg->base.cra_ctxsize =sizeof (struct drbg_state ); alg->base.cra_module =THIS_MODULE ; alg->base.cra_init = drbg_kcapi_init; alg->base.cra_exit = drbg_kcapi_cleanup;
Signature · 1 line
2.53.0
PATCH 6/38 crypto: drbg - Remove always-enabled symbol CRYPTO_DRBG_HMAC
In reply to Eric BiggersThe kconfig symbol CRYPTO_DRBG_HMAC is always enabled when CRYPTO_DRBG_MENU is enabled, and all checks for CRYPTO_DRBG_HMAC are in code conditional on CRYPTO_DRBG_MENU. Thus, the only purpose of the CRYPTO_DRBG_HMAC symbol is to select CRYPTO_HMAC and CRYPTO_SHA512.
Move those two selections to CRYPTO_DRBG_MENU, remove the checks for CRYPTO_DRBG_HMAC, and remove the CRYPTO_DRBG_HMAC symbol itself.
Note that this also fixes an issue where CRYPTO_HMAC and CRYPTO_SHA512 were unnecessarily being forced to built-in when CRYPTO_DRBG=m.
--- crypto/Kconfig | 10 +++------- crypto/drbg.c | 15 --------------- 2 files changed, 3 insertions(+), 22 deletions(-)
crypto/Kconfig +3 -7
@@ -1120,16 +1120,10 @@ menuconfig CRYPTO_DRBG_MENU In the following submenu, one or more of the DRBG types must be selected. if CRYPTO_DRBG_MENU -config CRYPTO_DRBG_HMAC - bool - default y - select CRYPTO_HMAC - select CRYPTO_SHA512 - config CRYPTO_DRBG_HASH bool "Hash_DRBG" select CRYPTO_SHA256 help Hash_DRBG variant as defined in NIST SP800-90A.
@@ -1145,12 +1139,14 @@ config CRYPTO_DRBG_CTR This uses the AES cipher algorithm with the counter block mode. config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU - select CRYPTO_RNG + select CRYPTO_HMAC select CRYPTO_JITTERENTROPY + select CRYPTO_RNG + select CRYPTO_SHA512 endif # if CRYPTO_DRBG_MENU config CRYPTO_JITTERENTROPY tristate "CPU Jitter Non-Deterministic RNG (Random Number Generator)"
crypto/drbg.c +0 -15
@@ -159,11 +159,10 @@ static const struct drbg_core drbg_cores[] = { .blocklen_bytes = 32, .cra_name = "sha256", .backend_cra_name = "sha256", },#endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_HMAC { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ .blocklen_bytes = 48, .cra_name = "hmac_sha384",
@@ -179,11 +178,10 @@ static const struct drbg_core drbg_cores[] = { .statelen = 64, /* block length of cipher */ .blocklen_bytes = 64, .cra_name = "hmac_sha512", .backend_cra_name = "hmac(sha512)", }, -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ };static int drbg_uninstantiate (struct drbg_state *drbg);/******************************************************************
@@ -404,20 +402,17 @@ static const struct drbg_state_ops drbg_ctr_ops = {/****************************************************************** * HMAC DRBG callback functions ******************************************************************/ -#if defined(CONFIG_CRYPTO_DRBG_HASH ) || defined(CONFIG_CRYPTO_DRBG_HMAC )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); -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ -#ifdef CONFIG_CRYPTO_DRBG_HMAC #define CRYPTO_DRBG_HMAC_STRING "HMAC "MODULE_ALIAS_CRYPTO ("drbg_pr_hmac_sha512" );MODULE_ALIAS_CRYPTO ("drbg_nopr_hmac_sha512" );MODULE_ALIAS_CRYPTO ("drbg_pr_hmac_sha384" );MODULE_ALIAS_CRYPTO ("drbg_nopr_hmac_sha384" );
@@ -525,11 +520,10 @@ static const struct drbg_state_ops drbg_hmac_ops = { .update = drbg_hmac_update, .generate = drbg_hmac_generate, .crypto_init = drbg_init_hash_kernel, .crypto_fini = drbg_fini_hash_kernel, }; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ /****************************************************************** * Hash DRBG callback functions ******************************************************************/
@@ -1044,15 +1038,13 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) {int ret = -ENOMEM ;unsigned int sb_size =0 ;switch (drbg->core->flags &DRBG_TYPE_MASK ) { -#ifdef CONFIG_CRYPTO_DRBG_HMAC case DRBG_HMAC : drbg->d_ops = &drbg_hmac_ops;break ; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ #ifdef CONFIG_CRYPTO_DRBG_HASH case DRBG_HASH : drbg->d_ops = &drbg_hash_ops;break ;#endif /* CONFIG_CRYPTO_DRBG_HASH */
@@ -1429,11 +1421,10 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm,/*************************************************************** * Kernel crypto API cipher invocations requested by DRBG ***************************************************************/ -#if defined(CONFIG_CRYPTO_DRBG_HASH ) || defined(CONFIG_CRYPTO_DRBG_HMAC )struct sdesc {struct shash_desc shash; };static int drbg_init_hash_kernel (struct drbg_state *drbg)
@@ -1489,11 +1480,10 @@ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,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); } -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ #ifdef CONFIG_CRYPTO_DRBG_CTR static int drbg_fini_sym_kernel (struct drbg_state *drbg) {struct aes_enckey *aeskey = drbg->priv_data;
@@ -1755,13 +1745,11 @@ static inline int __init drbg_healthcheck_sanity(void)drbg_convert_tfm_core ("drbg_nopr_ctr_aes256" , &coreref, &pr);#endif #ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core ("drbg_nopr_sha256" , &coreref, &pr);#endif -#ifdef CONFIG_CRYPTO_DRBG_HMAC drbg_convert_tfm_core ("drbg_nopr_hmac_sha512" , &coreref, &pr); -#endif drbg = kzalloc_obj(struct drbg_state);if (!drbg)return -ENOMEM ;
@@ -1885,13 +1873,10 @@ static void __exit drbg_exit(void)module_init (drbg_init);module_exit (drbg_exit);#ifndef CRYPTO_DRBG_HASH_STRING #define CRYPTO_DRBG_HASH_STRING ""#endif -#ifndef CRYPTO_DRBG_HMAC_STRING -#define CRYPTO_DRBG_HMAC_STRING "" -#endif #ifndef CRYPTO_DRBG_CTR_STRING #define CRYPTO_DRBG_CTR_STRING ""#endif MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Stephan Mueller <[email protected]>" );
Signature · 1 line
2.53.0
PATCH 7/38 crypto: drbg - Remove broken commented-out code
In reply to Eric BiggersThis commented-out code doesn't compile. Even if it did, it wouldn't actually do what it was apparently intended to do, seeing as the "test" for "drbg_pr_hmac_sha512" and "drbg_pr_ctr_aes256" is alg_test_null().
Just delete it to avoid keeping broken code around, and so that there isn't any perceived need to try to update it as the DRBG code is refactored.
--- crypto/drbg.c | 29 ----------------------------- 1 file changed, 29 deletions(-)
crypto/drbg.c +0 -29
@@ -1217,40 +1217,11 @@ static int drbg_generate(struct drbg_state *drbg,* 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. -* -* Albeit the following code is commented out, it is provided in -* case somebody has a need to implement the test of 11.3.3. */ -#if 0 -if (drbg->reseed_ctr && !(drbg->reseed_ctr %4096 )) { -int err =0 ; -pr_devel ("DRBG: start to perform self test\n" ); -if (drbg->core->flags &DRBG_HMAC ) - err =alg_test ("drbg_pr_hmac_sha512" , -"drbg_pr_hmac_sha512" ,0 ,0 ); -else if (drbg->core->flags &DRBG_CTR ) - err =alg_test ("drbg_pr_ctr_aes256" , -"drbg_pr_ctr_aes256" ,0 ,0 ); -else - err =alg_test ("drbg_pr_sha256" , -"drbg_pr_sha256" ,0 ,0 ); -if (err) { -pr_err ("DRBG: periodical self test failed\n" ); -/* -* uninstantiate implies that from now on, only errors -* are returned when reusing this DRBG cipher handle -*/ -drbg_uninstantiate (drbg); -return 0 ; - }else { -pr_devel ("DRBG: self test successful\n" ); - } - } -#endif /* * All operations were successful, return 0 as mandated by * the kernel crypto API interface. */
Signature · 1 line
2.53.0
PATCH 8/38 crypto: drbg - Remove unhelpful helper functions
In reply to Eric BiggersFold the contents of the inline functions crypto_drbg_get_bytes_addtl(), crypto_drbg_get_bytes_addtl_test(), and crypto_drbg_reset_test() into their only caller in drbg_cavs_test(). It ends up being much simpler.
--- crypto/drbg.c | 15 +++------ crypto/testmgr.c | 34 ++++++------------- include/crypto/drbg.h | 76 ------------------------------------------- 3 files changed, 15 insertions(+), 110 deletions(-)
crypto/drbg.c +5 -10
@@ -53,44 +53,39 @@* 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); +* 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]; -* struct drbg_string pers; * char personalization[11] = "some-string"; * -* drbg_string_fill(&pers, personalization, strlen(personalization)); * 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); +* 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"; -* string drbg_string addtl; * -* drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); * drng = crypto_alloc_rng(drng_name, 0, 0); -* // The following call is a wrapper to crypto_rng_get_bytes() and returns -* // the same error codes. -* err = crypto_drbg_get_bytes_addtl(drng, &data, DATALEN, &addtl); +* err = crypto_rng_generate(drng, addtl_string, strlen(addtl_string), +data, DATALEN); * crypto_free_rng(drng); * * * Usage with personalization and additional information strings * -------------------------------------------------------------
crypto/testmgr.c +10 -24
@@ -3485,12 +3485,10 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver,static int drbg_cavs_test (const struct drbg_testvec *test,int pr,const char *driver,u32 type,u32 mask) {int ret = -EAGAIN ;struct crypto_rng *drng; -struct drbg_test_data test_data; -struct drbg_string addtl, pers, testentropy;unsigned char *buf =kzalloc (test->expectedlen,GFP_KERNEL );if (!buf)return -ENOMEM ;
@@ -3502,43 +3500,31 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,printk (KERN_ERR "alg: drbg: could not allocate DRNG handle for " "%s\n" , driver);return PTR_ERR (drng); } - test_data.testentropy = &testentropy; -drbg_string_fill (&testentropy, test->entropy, test->entropylen); -drbg_string_fill (&pers, test->pers, test->perslen); - ret =crypto_drbg_reset_test (drng, &pers, &test_data); +crypto_rng_set_entropy (drng, test->entropy, test->entropylen); + ret =crypto_rng_reset (drng, test->pers, test->perslen);if (ret) {printk (KERN_ERR "alg: drbg: Failed to reset rng\n" ); goto outbuf; } -drbg_string_fill (&addtl, test->addtla, test->addtllen); -if (pr) { -drbg_string_fill (&testentropy, test->entpra, test->entprlen); - ret =crypto_drbg_get_bytes_addtl_test (drng, - buf, test->expectedlen, &addtl, &test_data); - }else { - ret =crypto_drbg_get_bytes_addtl (drng, - buf, test->expectedlen, &addtl); - } +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; } -drbg_string_fill (&addtl, test->addtlb, test->addtllen); -if (pr) { -drbg_string_fill (&testentropy, test->entprb, test->entprlen); - ret =crypto_drbg_get_bytes_addtl_test (drng, - buf, test->expectedlen, &addtl, &test_data); - }else { - ret =crypto_drbg_get_bytes_addtl (drng, - buf, test->expectedlen, &addtl); - } +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); goto outbuf; }
include/crypto/drbg.h +0 -76
96 lines not on this page · raw message
Signature · 1 line
2.53.0
PATCH 9/38 crypto: drbg - Remove obsolete FIPS 140-2 continuous test
In reply to Eric BiggersFIPS 140-2 required that a continuous test for repeated outputs be done on both "Approved RNGs" and "Non-Approved RNGs".
That's apparently why crypto/drbg.c does such a test on the bytes it pulls from get_random_bytes(), despite get_random_bytes() being a "Non-Approved RNG" that is credited with zero entropy for FIPS purposes. (From FIPS's point of view, the "Approved RNG" is jitterentropy.)
FIPS 140-3 "modernized" the continuous RNG test requirements. They're now a bit more sophisticated, requiring both an "Adaptive Proportion Test" and a "Repetition Count Test".
At the same time, FIPS 140-3 doesn't require continuous RNG tests on "Non-Approved RNGs" if a "vetted conditioning component" is used. The SP800-90A DRBGs are exactly such a vetted conditioning component, by their design. (In the case of HASH_DRBG and CTR_DRBG, the derivation function does have to be implemented. But the kernel does that.)
In other words: from FIPS 140-3's point of view, get_random_bytes() still produces zero entropy, but the way the DRBG combines those bytes with the jitterentropy bytes preserves all the "approved" entropy from jitterentropy. Thus no test for get_random_bytes() is required.
Seeing as FIPS 140-2 certificates stopped being issued in 2021 in favor of FIPS 140-3, this means this code is obsolete. Remove it.
--- crypto/drbg.c | 78 ++----------------------------------------- include/crypto/drbg.h | 2 -- 2 files changed, 2 insertions(+), 78 deletions(-)
crypto/drbg.c +2 -76
@@ -203,59 +203,10 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags)default :return 32 ; } } -/* -* FIPS 140-2 continuous self test for the noise source -* The test is performed on the noise source input data. Thus, the function -* implicitly knows the size of the buffer to be equal to the security -* strength. -* -* Note, this function disregards the nonce trailing the entropy data during -* initial seeding. -* -* drbg->drbg_mutex must have been taken. -* -* @drbg DRBG handle -* @entropy buffer of seed data to be checked -* -* return: -* %true on success -* %false when the CTRNG is not yet primed -*/ -static bool drbg_fips_continuous_test (struct drbg_state *drbg, -const unsigned char *entropy) - __must_hold(&drbg->drbg_mutex) -{ -unsigned short entropylen =drbg_sec_strength (drbg->core->flags); - -if (!IS_ENABLED (CONFIG_CRYPTO_FIPS )) -return true; - -/* skip test if we test the overall system */ -if (list_empty (&drbg->test_data.list)) -return true; -/* only perform test in FIPS mode */ -if (!fips_enabled) -return true; - -if (!drbg->fips_primed) { -/* Priming of FIPS test */ -memcpy (drbg->prev, entropy, entropylen); - drbg->fips_primed = true; -/* priming: another round is needed */ -return false; - } -if (!memcmp (drbg->prev, entropy, entropylen)) -panic ("DRBG continuous self test failed\n" ); -memcpy (drbg->prev, entropy, entropylen); - -/* the test shall pass when the two values are not equal */ -return true; -} -/****************************************************************** * CTR DRBG callback functions ******************************************************************/ #ifdef CONFIG_CRYPTO_DRBG_CTR
@@ -831,20 +782,10 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, }return ret; } -static inline void drbg_get_random_bytes (struct drbg_state *drbg, -unsigned char *entropy, -unsigned int entropylen) - __must_hold(&drbg->drbg_mutex) -{ -do -get_random_bytes (entropy, entropylen); -while (!drbg_fips_continuous_test (drbg, entropy)); -} -static int drbg_seed_from_random (struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) {struct drbg_string data;LIST_HEAD (seedlist);
@@ -856,11 +797,11 @@ static int drbg_seed_from_random(struct drbg_state *drbg)BUG_ON (entropylen >sizeof (entropy));drbg_string_fill (&data, entropy, entropylen);list_add_tail (&data.list, &seedlist); -drbg_get_random_bytes (drbg, entropy, entropylen); +get_random_bytes (entropy, entropylen); ret =__drbg_seed (drbg, &seedlist, true,DRBG_SEED_STATE_FULL );memzero_explicit (entropy, entropylen);return ret;
@@ -935,11 +876,11 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,/* Get seed from in-kernel /dev/urandom */ if (!rng_is_initialized ()) new_seed_state =DRBG_SEED_STATE_PARTIAL ; -drbg_get_random_bytes (drbg, entropy, entropylen); +get_random_bytes (entropy, entropylen);if (!drbg->jent) {drbg_string_fill (&data1, entropy, entropylen);pr_devel ("DRBG: (re)seeding with %u bytes of entropy\n" , entropylen);
@@ -1016,15 +957,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)kfree_sensitive (drbg->scratchpadbuf); drbg->scratchpadbuf =NULL ; drbg->reseed_ctr =0 ; drbg->d_ops =NULL ; drbg->core =NULL ; -if (IS_ENABLED (CONFIG_CRYPTO_FIPS )) { -kfree_sensitive (drbg->prev); - drbg->prev =NULL ; - drbg->fips_primed = false; - } }/* * Allocate all sub-structures for a DRBG state. * The DRBG state structure must already be allocated.
@@ -1086,20 +1022,10 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) goto fini; } drbg->scratchpad =PTR_ALIGN (drbg->scratchpadbuf, ret +1 ); } -if (IS_ENABLED (CONFIG_CRYPTO_FIPS )) { - drbg->prev =kzalloc (drbg_sec_strength (drbg->core->flags), -GFP_KERNEL ); -if (!drbg->prev) { - ret = -ENOMEM ; - goto fini; - } - drbg->fips_primed = false; - } -return 0 ; fini: drbg->d_ops->crypto_fini (drbg); err:
include/crypto/drbg.h +0 -2
@@ -107,12 +107,10 @@ struct drbg_state {struct scatterlist sg_in, sg_out;/* CTR mode SGLs */ enum drbg_seed_state seeded;/* DRBG fully seeded? */ unsigned long last_seed_time;bool pr;/* Prediction resistance enabled? */ -bool fips_primed;/* Continuous test primed? */ -unsigned char *prev;/* FIPS 140-2 continuous test value */ struct crypto_rng *jent;const struct drbg_state_ops *d_ops;const struct drbg_core *core;struct drbg_string test_data; };
Signature · 1 line
2.53.0
PATCH 10/38 crypto: drbg - Fold include/crypto/drbg.h into crypto/drbg.c
In reply to Eric Biggersinclude/crypto/drbg.h no longer contains anything that is used externally to crypto/drbg.c. Therefore, fold it into crypto/drbg.c.
--- crypto/drbg.c | 132 ++++++++++++- crypto/testmgr.c | 3 +- include/crypto/drbg.h | 181 ------------------ .../crypto/chacha20-s390/test-cipher.c | 1 - 4 files changed, 132 insertions(+), 185 deletions(-) delete mode 100644 include/crypto/drbg.h
crypto/drbg.c +131 -1
@@ -90,18 +90,148 @@* Usage with personalization and additional information strings * ------------------------------------------------------------- * Just mix both scenarios above. */ -#include <crypto/drbg.h> #include <crypto/df_sp80090a.h> #include <crypto/internal/cipher.h> +#include <crypto/internal/drbg.h> +#include <crypto/internal/rng.h> +#include <crypto/hash.h> +#include <crypto/skcipher.h> +#include <linux/fips.h> #include <linux/kernel.h> #include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/scatterlist.h> #include <linux/string_choices.h> #include <linux/unaligned.h> +struct drbg_state ; +typedef uint32_t drbg_flag_t ; + +struct drbg_core { +drbg_flag_t flags;/* flags for the cipher */ +__u8 statelen;/* maximum state length */ +__u8 blocklen_bytes;/* block size of output in bytes */ +char cra_name[CRYPTO_MAX_ALG_NAME ];/* mapping to kernel crypto API */ +/* kernel crypto API backend cipher name */ +char backend_cra_name[CRYPTO_MAX_ALG_NAME ]; +}; + +struct drbg_state_ops { +int (*update)(struct drbg_state *drbg,struct list_head *seed, +int reseed); +int (*generate)(struct drbg_state *drbg, +unsigned char *buf,unsigned int buflen, +struct list_head *addtl); +int (*crypto_init)(struct drbg_state *drbg); +int (*crypto_fini)(struct drbg_state *drbg); + +}; + +enum drbg_seed_state { +DRBG_SEED_STATE_UNSEEDED , +DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ +DRBG_SEED_STATE_FULL , +}; + +struct drbg_state { +struct mutex drbg_mutex;/* lock around DRBG */ +unsigned char *V;/* internal state 10.1.1.1 1a) */ +unsigned char *Vbuf; +/* hash: static value 10.1.1.1 1b) hmac / ctr: key */ +unsigned char *C; +unsigned char *Cbuf; +/* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ +size_t reseed_ctr; +size_t reseed_threshold; +/* some memory the DRBG can use for its operation */ +unsigned char *scratchpad; +unsigned char *scratchpadbuf; +void *priv_data;/* Cipher handle */ + +struct crypto_skcipher *ctr_handle;/* CTR mode cipher handle */ +struct skcipher_request *ctr_req;/* CTR mode request handle */ +__u8 *outscratchpadbuf;/* CTR mode output scratchpad */ +__u8 *outscratchpad;/* CTR mode aligned outbuf */ +struct crypto_wait ctr_wait;/* CTR mode async wait obj */ +struct scatterlist sg_in, sg_out;/* CTR mode SGLs */ + +enum drbg_seed_state seeded;/* DRBG fully seeded? */ +unsigned long last_seed_time; +bool pr;/* Prediction resistance enabled? */ +struct crypto_rng *jent; +const struct drbg_state_ops *d_ops; +const struct drbg_core *core; +struct drbg_string test_data; +}; + +static inline __u8 drbg_statelen (struct drbg_state *drbg) +{ +if (drbg && drbg->core) +return drbg->core->statelen; +return 0 ; +} + +static inline __u8 drbg_blocklen (struct drbg_state *drbg) +{ +if (drbg && drbg->core) +return drbg->core->blocklen_bytes; +return 0 ; +} + +static inline __u8 drbg_keylen (struct drbg_state *drbg) +{ +if (drbg && drbg->core) +return (drbg->core->statelen - drbg->core->blocklen_bytes); +return 0 ; +} + +static inline size_t drbg_max_request_bytes (struct drbg_state *drbg) +{ +/* SP800-90A requires the limit 2**19 bits, but we return bytes */ +return (1 <<16 ); +} + +/* +* SP800-90A allows implementations to support additional info / personalization +* strings of up to 2**35 bits. Implementations can have a smaller maximum. We +* use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a +* size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. +*/ +static inline size_t drbg_max_addtl (struct drbg_state *drbg) +{ +return U32_MAX -1 ; +} + +static inline size_t drbg_max_requests (struct drbg_state *drbg) +{ +/* SP800-90A requires 2**48 maximum requests before reseeding */ +return (1 <<20 ); +} + +/* DRBG type flags */ +#define DRBG_CTR ((drbg_flag_t)1<<0) +#define DRBG_HMAC ((drbg_flag_t)1<<1) +#define DRBG_HASH ((drbg_flag_t)1<<2) +#define DRBG_TYPE_MASK (DRBG_CTR | DRBG_HMAC | DRBG_HASH) +/* DRBG strength flags */ +#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) +#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) +#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) +#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ + DRBG_STRENGTH256) + +enum drbg_prefixes { +DRBG_PREFIX0 =0x00 , +DRBG_PREFIX1 , +DRBG_PREFIX2 , +DRBG_PREFIX3 +}; +/*************************************************************** * Backend cipher definitions available to DRBG ***************************************************************/ /*
crypto/testmgr.c +1 -2
@@ -26,17 +26,16 @@#include <linux/prandom.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/uio.h> -#include <crypto/rng.h> -#include <crypto/drbg.h> #include <crypto/akcipher.h> #include <crypto/kpp.h> #include <crypto/acompress.h> #include <crypto/sig.h> #include <crypto/internal/cipher.h> +#include <crypto/internal/rng.h> #include <crypto/internal/simd.h> #include "internal.h" MODULE_IMPORT_NS ("CRYPTO_INTERNAL" );
include/crypto/drbg.h deleted +0 -181
181 lines not on this page · raw message
tools/testing/crypto/chacha20-s390/test-cipher.c +0 -1
@@ -9,11 +9,10 @@#include <asm/smp.h> #include <crypto/skcipher.h> #include <crypto/akcipher.h> #include <crypto/acompress.h> #include <crypto/rng.h> -#include <crypto/drbg.h> #include <crypto/kpp.h> #include <crypto/internal/simd.h> #include <crypto/chacha.h> #include <crypto/aead.h> #include <crypto/hash.h>
Signature · 1 line
2.53.0
PATCH 11/38 crypto: drbg - Remove import of crypto_cipher functions
In reply to Eric BiggersThe inclusion of <crypto/internal/cipher.h> and the import of the internal crypto namespace became unnecessary in commit ba0570bdf1d9 ("crypto: drbg - Replace AES cipher calls with library calls").
--- crypto/drbg.c | 2 -- 1 file changed, 2 deletions(-)
crypto/drbg.c +0 -2
@@ -91,11 +91,10 @@* ------------------------------------------------------------- * Just mix both scenarios above. */ #include <crypto/df_sp80090a.h> -#include <crypto/internal/cipher.h> #include <crypto/internal/drbg.h> #include <crypto/internal/rng.h> #include <crypto/hash.h> #include <crypto/skcipher.h> #include <linux/fips.h>
@@ -1906,6 +1905,5 @@ MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) ""using following cores: " CRYPTO_DRBG_HASH_STRING CRYPTO_DRBG_HMAC_STRING CRYPTO_DRBG_CTR_STRING);MODULE_ALIAS_CRYPTO ("stdrng" ); -MODULE_IMPORT_NS ("CRYPTO_INTERNAL" );
Signature · 1 line
2.53.0
PATCH 12/38 crypto: drbg - Remove support for CTR_DRBG
In reply to Eric BiggersRemove the support for CTR_DRBG. It's likely unused code, seeing as HMAC_DRBG is always enabled and prioritized over it unless NETLINK_CRYPTO is used to change the algorithm priorities.
There's also no compelling reason to support more than one of [HMAC_DRBG, HASH_DRBG, CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway.
Switching to CTR_DRBG doesn't seem all that compelling, either. While it's often the fastest NIST DRBG, it has several disadvantages:
- CTR_DRBG uses AES. Some platforms don't have AES acceleration at all, causing a fallback to the table-based AES code which is very slow and can be vulnerable to cache-timing attacks. In contrast, HMAC_DRBG uses primitives that are consistently constant-time.
- CTR_DRBG is usually considered to be somewhat less cryptographically robust than HMAC_DRBG. Granted, HMAC_DRBG isn't all that great either, e.g. given the negative result from Woodage & Shumow (2018)
(https://eprint.iacr.org/2018/349.pdf), but that can be worked around.
- CTR_DRBG is more complex than HMAC_DRBG, risking bugs. Indeed, while reviewing the CTR_DRBG code, I found two bugs, including one where it can return success while leaving the output buffer uninitialized.
- The kernel's implementation of CTR_DRBG uses an "ctr(aes)" crypto_skcipher and relies on it returning the next counter value.
That's fragile, and indeed historically many "ctr(aes)"
crypto_skcipher implementations haven't done that. E.g. see
commit 511306b2d075 ("crypto: arm/aes-ce - update IV after partial final CTR block"), commit fa5fd3afc7e6 ("crypto: arm64/aes-blk - update IV after partial final CTR block"), commit 371731ec2179 ("crypto: atmel-aes - Fix saving of IV for CTR mode"), commit 25baaf8e2c93 ("crypto: crypto4xx - fix ctr-aes missing output IV"), commit 334d37c9e263 ("crypto: caam - update IV using HW support"),
commit 0a4491d3febe ("crypto: chelsio - count incomplete block in IV"), commit e8e3c1ca57d4 ("crypto: s5p - update iv after AES-CBC op end").
I.e., there were many years where the kernel's CTR_DRBG code (if it were to have actually been used) repeated outputs on some platforms.
AES-CTR also uses a 128-bit counter, which creates overflow edge cases that are sometimes gotten wrong. E.g. see commit 009b30ac7444 ("crypto: vmx - CTR: always increment IV as quadword").
So, while switching to CTR_DRBG for performance reasons isn't completely out of the question (notably BoringSSL uses it), it would take quite a bit more work to create a solid implementation of it in the kernel, including a more solid implementation of AES-CTR itself (in lib/crypto/, with a scalar bit-sliced fallback, etc). Since HMAC_DRBG has always been the default NIST DRBG variant in the kernel and is in a better state, let's just standardize on it for now.
--- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/mips/configs/decstation_64_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/decstation_r4k_defconfig | 1 - crypto/Kconfig | 8 - crypto/drbg.c | 332 +-------------------- crypto/testmgr.c | 37 --- crypto/testmgr.h | 252 ---------------- include/crypto/internal/drbg.h | 3 + 20 files changed, 9 insertions(+), 638 deletions(-)
arch/m68k/configs/amiga_defconfig +0 -1
@@ -549,11 +549,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/apollo_defconfig +0 -1
@@ -504,11 +504,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/atari_defconfig +0 -1
@@ -526,11 +526,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/bvme6000_defconfig +0 -1
@@ -496,11 +496,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/hp300_defconfig +0 -1
@@ -506,11 +506,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mac_defconfig +0 -1
@@ -525,11 +525,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/multi_defconfig +0 -1
@@ -612,11 +612,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mvme147_defconfig +0 -1
@@ -496,11 +496,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mvme16x_defconfig +0 -1
@@ -497,11 +497,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/q40_defconfig +0 -1
@@ -515,11 +515,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/sun3_defconfig +0 -1
@@ -494,11 +494,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/sun3x_defconfig +0 -1
@@ -494,11 +494,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/mips/configs/decstation_64_defconfig +0 -1
@@ -198,9 +198,8 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
arch/mips/configs/decstation_defconfig +0 -1
@@ -193,10 +193,9 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
arch/mips/configs/decstation_r4k_defconfig +0 -1
@@ -193,10 +193,9 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
crypto/Kconfig +0 -8
@@ -1128,18 +1128,10 @@ config CRYPTO_DRBG_HASH help Hash_DRBG variant as defined in NIST SP800-90A. This uses the SHA-1, SHA-256, SHA-384, or SHA-512 hash algorithms. -config CRYPTO_DRBG_CTR - bool "CTR_DRBG" - select CRYPTO_DF80090A - help - CTR_DRBG variant as defined in NIST SP800-90A. - - This uses the AES cipher algorithm with the counter block mode. - config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU select CRYPTO_HMAC select CRYPTO_JITTERENTROPY
crypto/drbg.c +6 -326
486 lines not on this page · raw message
crypto/testmgr.c +0 -37
@@ -4636,31 +4636,10 @@ static const struct alg_test_desc alg_test_descs[] = { .kpp = __VECS(dh_tv_template) } }, { .alg = "digest_null", .test = alg_test_null, - }, { - .alg = "drbg_nopr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes128_tv_template) - } - }, { - .alg = "drbg_nopr_ctr_aes192", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes192_tv_template) - } - }, { - .alg = "drbg_nopr_ctr_aes256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes256_tv_template) - } }, { .alg = "drbg_nopr_hmac_sha256", .test = alg_test_drbg, .fips_allowed = 1, .suite = {
@@ -4695,26 +4674,10 @@ static const struct alg_test_desc alg_test_descs[] = { .fips_allowed = 1 }, { .alg = "drbg_nopr_sha512", .fips_allowed = 1, .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_ctr_aes128_tv_template) - } - }, { - /* covered by drbg_pr_ctr_aes128 test */ - .alg = "drbg_pr_ctr_aes192", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes256", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, .fips_allowed = 1, .suite = {
crypto/testmgr.h +0 -252
272 lines not on this page · raw message
include/crypto/internal/drbg.h +3 -0
@@ -7,10 +7,13 @@*/ #ifndef _INTERNAL_DRBG_H#define _INTERNAL_DRBG_H +#include <linux/list.h> +#include <linux/types.h> +/* * Concatenation Helper and string operation helper * * SP800-90A requires the concatenation of different data. To avoid copying * buffers around or allocate additional memory, the following data structure
Signature · 1 line
2.53.0
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
Quoted 55 lines · Eric Biggers
Remove the support for
CTR_DRBG. It's likely unused code, seeing asHMAC_DRBGis always enabled and prioritized over it unlessNETLINK_CRYPTOis used to change the algorithm priorities.There's also no compelling reason to support more than one of [
HMAC_DRBG,HASH_DRBG,CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway.Switching to
CTR_DRBGdoesn't seem all that compelling, either. While it's often the fastest NIST DRBG, it has several disadvantages:-
CTR_DRBGuses AES. Some platforms don't have AES acceleration at all, causing a fallback to the table-based AES code which is very slow and can be vulnerable to cache-timing attacks. In contrast,HMAC_DRBGuses primitives that are consistently constant-time.-
CTR_DRBGis usually considered to be somewhat less cryptographically robust thanHMAC_DRBG. Granted,HMAC_DRBGisn't all that great either, e.g. given the negative result from Woodage & Shumow (2018)
(https://eprint.iacr.org/2018/349.pdf), but that can be worked around.-
CTR_DRBGis more complex thanHMAC_DRBG, risking bugs. Indeed, while reviewing theCTR_DRBGcode, I found two bugs, including one where it can return success while leaving the output buffer uninitialized.- The kernel's implementation of
CTR_DRBGuses an "ctr(aes)"crypto_skcipherand relies on it returning the next counter value.
That's fragile, and indeed historically many "ctr(aes)"
crypto_skcipherimplementations haven't done that. E.g. see
commit511306b2d075("crypto: arm/aes-ce - update IV after partial final CTR block"), commitfa5fd3afc7e6("crypto: arm64/aes-blk - update IV after partial final CTR block"), commit371731ec2179("crypto: atmel-aes - Fix saving of IV for CTR mode"), commit25baaf8e2c93("crypto: crypto4xx - fix ctr-aes missing output IV"), commit334d37c9e263("crypto: caam - update IV using HW support"),
commit0a4491d3febe("crypto: chelsio - count incomplete block in IV"), commite8e3c1ca57d4("crypto: s5p - update iv after AES-CBC op end").I.e., there were many years where the kernel's
CTR_DRBGcode (if it were to have actually been used) repeated outputs on some platforms.AES-CTR also uses a 128-bit counter, which creates overflow edge cases that are sometimes gotten wrong. E.g. see commit
009b30ac7444("crypto: vmx - CTR: always increment IV as quadword").So, while switching to
CTR_DRBGfor performance reasons isn't completely out of the question (notably BoringSSL uses it), it would take quite a bit more work to create a solid implementation of it in the kernel, including a more solid implementation of AES-CTR itself (inlib/crypto/, with a scalar bit-sliced fallback, etc). SinceHMAC_DRBGhas always been the default NIST DRBG variant in the kernel and is in a better state, let's just standardize on it for now.Signed-off-by Eric Biggers <[email protected]>
Quoted 12 lines
arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 -
Gr{oetje,eeting}s,
Geert
Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected] In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
In reply to Eric BiggersAm Montag, 20. April 2026, 08:33:56 Mitteleuropäische Sommerzeit schrieb Eric Biggers:
Hi Eric,
Quoted 3 lines
Remove the support for
CTR_DRBG. It's likely unused code, seeing asHMAC_DRBGis always enabled and prioritized over it unlessNETLINK_CRYPTOis used to change the algorithm priorities.
Just as an FYI: the CTR DRBG implementation is used, because it provides massive superior performance. The CTR DRBG implementation is lined up to use the AES-CTR mode directly. If you have an accelerated implementation like AES- NI or ARM-CE, your performance increase is significant.
For example, on my M4 development system, the generation of 1GB of data from the CTR DRBG takes 90ms whereas the HMAC DRBG takes more than 4 seconds.
The default of HMAC DRBG, however, was used since it has a simple logic and smaller code.
Ciao
Stephan
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
Quoted 14 lines · Stephan Mueller
Am Montag, 20. April 2026, 08:33:56 Mitteleuropäische Sommerzeit schrieb Eric Biggers:
Hi Eric,
Quoted 3 lines
Remove the support for
CTR_DRBG. It's likely unused code, seeing asHMAC_DRBGis always enabled and prioritized over it unlessNETLINK_CRYPTOis used to change the algorithm priorities.Just as an FYI: the CTR DRBG implementation is used, because it provides massive superior performance. The CTR DRBG implementation is lined up to use the AES-CTR mode directly. If you have an accelerated implementation like AES- NI or ARM-CE, your performance increase is significant.
Quoted 5 lines
For example, on my M4 development system, the generation of 1GB of data from the CTR DRBG takes 90ms whereas the HMAC DRBG takes more than 4 seconds.
The default of HMAC DRBG, however, was used since it has a simple logic and smaller code.
I guess I have to ask: by "it is used", do you mean that it's used by a significant number of users, or is it more of a personal thing where you happen to be personally using it? Note that the only way to select it is directly by driver name (which has no in-kernel users), by running a custom userspace program that uses NETLINK_CRYPTO to modify the algorithm priorities. I'm sure you know how to do the NETLINK_CRYPTO thing, but this very much seems like an idiosyncratic expert-level configuration that isn't really used in practice, similar to some other things that you've added like CONFIG_CRYPTO_JITTERENTROPY_MEMSIZE_*.
And even if it's being used, does it really need to be? Do you really need more than 250 MB/s of "FIPS-approved" random numbers, and from the kernel (not a userspace library)?
I also don't think we actually have much choice, given that we don't currently have a reliably correct implementation of CTR_DRBG anyway, and that takes priority over everything else. As I explained in detail in this patch, this just hasn't been something that's ever been done. It sometimes returns success on failure, it sometimes isn't constant-time, and it used to repeat output on some platforms (and maybe even still does). Not particularly great properties for a RNG.
While a reliable implementation of CTR_DRBG is possible (BoringSSL does it, for example), the reality is it would take quite a bit more work.
- Eric
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
Am Montag, 20. April 2026, 19:47:13 Mitteleuropäische Sommerzeit schrieb Eric Biggers:
Hi Eric,
Quoted 19 lines · Stephan Mueller
Quoted 18 lines
Am Montag, 20. April 2026, 08:33:56 Mitteleuropäische Sommerzeit schrieb Eric Biggers:
Hi Eric,
Quoted 3 lines
Remove the support for
CTR_DRBG. It's likely unused code, seeing asHMAC_DRBGis always enabled and prioritized over it unlessNETLINK_CRYPTOis used to change the algorithm priorities.Just as an FYI: the CTR DRBG implementation is used, because it provides massive superior performance. The CTR DRBG implementation is lined up to use the AES-CTR mode directly. If you have an accelerated implementation like AES- NI or ARM-CE, your performance increase is significant.
For example, on my M4 development system, the generation of 1GB of data from the CTR DRBG takes 90ms whereas the HMAC DRBG takes more than 4 seconds.
Quoted 7 lines
Quoted 3 lines
The default of HMAC DRBG, however, was used since it has a simple logic and
smaller code.I guess I have to ask: by "it is used", do you mean that it's used by a significant number of users, or is it more of a personal thing where you happen to be personally using it?
I see it being used by vendors that I work with. I neither have concrete numbers or do I know how many machines are covered by it.
For any personal operations, I use the XDRBG anyway that would be separately implemented and provided.
Quoted 1 line
Note that the only way to select it
The selection would always be done during compile time for those vendors.
Quoted 10 lines
is directly by driver name (which has no in-kernel users), by running a custom userspace program that uses
NETLINK_CRYPTOto modify the algorithm priorities. I'm sure you know how to do theNETLINK_CRYPTOthing, but this very much seems like an idiosyncratic expert-level configuration that isn't really used in practice, similar to some other things that you've added like CONFIG_CRYPTO_JITTERENTROPY_MEMSIZE_*.And even if it's being used, does it really need to be? Do you really need more than 250 MB/s of "FIPS-approved" random numbers, and from the kernel (not a userspace library)?
The performance also implies that for a given number of bits, it uses less CPU cycles.
Ciao
Stephan
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
Quoted 3 lines · Stephan Mueller
Quoted 1 line
Note that the only way to select it
The selection would always be done during compile time for those vendors.
Again, even if someone were to want to do that for some reason, the status quo is that it's not supported. That is, currently you can set CONFIG_CRYPTO_DRBG_CTR=y, but "stdrng" is still HMAC_DRBG regardless.
- Eric
Re: [PATCH 12/38] crypto: drbg - Remove support for CTR_DRBG
Am Montag, 20. April 2026, 22:56:07 Mitteleuropäische Sommerzeit schrieb Eric Biggers:
Hi Eric,
Quoted 8 lines · Stephan Mueller
Quoted 3 lines
Quoted 1 line
Note that the only way to select it
The selection would always be done during compile time for those vendors.
Again, even if someone were to want to do that for some reason, the status quo is that it's not supported. That is, currently you can set
CONFIG_CRYPTO_DRBG_CTR=y, but "stdrng" is stillHMAC_DRBGregardless.
Changes to the priorities were applied to their kernels.
Quoted 2 lines
- Eric
Ciao
Stephan
PATCH 13/38 crypto: drbg - Remove support for HASH_DRBG
In reply to Eric BiggersRemove the support for HASH_DRBG. It's likely unused code, seeing as HMAC_DRBG is always enabled and prioritized over it unless NETLINK_CRYPTO is used to change the algorithm priorities.
There's also no compelling reason to support more than one of [HMAC_DRBG, HASH_DRBG, CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway.
Switching to HASH_DRBG doesn't seem all that compelling, either. For one, it's more complex than HMAC_DRBG.
Thus, let's just drop HASH_DRBG support and focus on HMAC_DRBG.
--- Documentation/crypto/api-samples.rst | 2 +- Documentation/crypto/userspace-if.rst | 2 +- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/mips/configs/decstation_64_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/decstation_r4k_defconfig | 1 - crypto/Kconfig | 8 - crypto/drbg.c | 348 +-------------------- crypto/testmgr.c | 32 -- crypto/testmgr.h | 296 ------------------ 21 files changed, 8 insertions(+), 695 deletions(-)
Documentation/crypto/api-samples.rst +1 -1
@@ -157,11 +157,11 @@ Code Example For Random Number Generator Usage static int get_random_numbers(u8 *buf, unsigned int len) { struct crypto_rng *rng = NULL; - char *drbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */ + char *drbg = "stdrng"; int ret; if (!buf || !len) { pr_debug("No output buffer provided\n"); return -EINVAL;
Documentation/crypto/userspace-if.rst +1 -1
@@ -295,11 +295,11 @@ follows: :: struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "rng", /* this selects the random number generator */ - .salg_name = "drbg_nopr_sha256" /* this is the RNG name */ + .salg_name = "stdrng" /* this is the RNG name */ }; Depending on the RNG type, the RNG must be seeded. The seed is provided using the setsockopt interface to set the key. The SP800-90A DRBGs do
arch/m68k/configs/amiga_defconfig +0 -1
@@ -548,11 +548,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/apollo_defconfig +0 -1
@@ -503,11 +503,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/atari_defconfig +0 -1
@@ -525,11 +525,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/bvme6000_defconfig +0 -1
@@ -495,11 +495,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/hp300_defconfig +0 -1
@@ -505,11 +505,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mac_defconfig +0 -1
@@ -524,11 +524,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/multi_defconfig +0 -1
@@ -611,11 +611,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mvme147_defconfig +0 -1
@@ -495,11 +495,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/mvme16x_defconfig +0 -1
@@ -496,11 +496,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/q40_defconfig +0 -1
@@ -514,11 +514,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/sun3_defconfig +0 -1
@@ -493,11 +493,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/m68k/configs/sun3x_defconfig +0 -1
@@ -493,11 +493,10 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_HW is not set
arch/mips/configs/decstation_64_defconfig +0 -1
@@ -197,9 +197,8 @@ CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
arch/mips/configs/decstation_defconfig +0 -1
@@ -192,10 +192,9 @@ CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
arch/mips/configs/decstation_r4k_defconfig +0 -1
@@ -192,10 +192,9 @@ CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set
crypto/Kconfig +0 -8
@@ -1120,18 +1120,10 @@ menuconfig CRYPTO_DRBG_MENU In the following submenu, one or more of the DRBG types must be selected. if CRYPTO_DRBG_MENU -config CRYPTO_DRBG_HASH - bool "Hash_DRBG" - select CRYPTO_SHA256 - help - Hash_DRBG variant as defined in NIST SP800-90A. - - This uses the SHA-1, SHA-256, SHA-384, or SHA-512 hash algorithms. - config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU select CRYPTO_HMAC select CRYPTO_JITTERENTROPY
crypto/drbg.c +6 -342
494 lines not on this page · raw message
crypto/testmgr.c +0 -32
@@ -4658,26 +4658,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_nopr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_sha256_tv_template) - } - }, { -/* covered by drbg_nopr_sha256 test */ - .alg = "drbg_nopr_sha384", - .test = alg_test_null, - .fips_allowed = 1 - }, { - .alg = "drbg_nopr_sha512", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, .fips_allowed = 1, .suite = {
@@ -4690,26 +4674,10 @@ static const struct alg_test_desc alg_test_descs[] = { .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", .test = alg_test_null, .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_sha256_tv_template) - } - }, { -/* covered by drbg_pr_sha256 test */ - .alg = "drbg_pr_sha384", - .test = alg_test_null, - .fips_allowed = 1 - }, { - .alg = "drbg_pr_sha512", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "ecb(aes)", .generic_driver = "ecb(aes-lib)", .test = alg_test_skcipher, .fips_allowed = 1,
crypto/testmgr.h +0 -296
316 lines not on this page · raw message
Signature · 1 line
2.53.0
Re: [PATCH 13/38] crypto: drbg - Remove support for HASH_DRBG
Quoted 16 lines · Eric Biggers
Remove the support for
HASH_DRBG. It's likely unused code, seeing asHMAC_DRBGis always enabled and prioritized over it unlessNETLINK_CRYPTOis used to change the algorithm priorities.There's also no compelling reason to support more than one of [
HMAC_DRBG,HASH_DRBG,CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway.Switching to
HASH_DRBGdoesn't seem all that compelling, either. For one, it's more complex thanHMAC_DRBG.Thus, let's just drop
HASH_DRBGsupport and focus onHMAC_DRBG.Signed-off-by Eric Biggers <[email protected]>
Quoted 12 lines
arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 -
Gr{oetje,eeting}s,
Geert
Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected] In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
PATCH 14/38 crypto: drbg - Flatten the DRBG menu
In reply to Eric BiggersNow that the menuconfig CRYPTO_DRBG_MENU has no options in it other than the hidden symbol CRYPTO_DRBG, remove it and move CRYPTO_DRBG to its parent menu. Give CRYPTO_DRBG an appropriate prompt and help text.
--- crypto/Kconfig | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
crypto/Kconfig +5 -12
@@ -1111,28 +1111,21 @@ config CRYPTO_ZSTD endmenu menu "Random number generation" -menuconfig CRYPTO_DRBG_MENU - tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" - help - DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) - - In the following submenu, one or more of the DRBG types must be selected. - -if CRYPTO_DRBG_MENU - config CRYPTO_DRBG - tristate - default CRYPTO_DRBG_MENU + tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" select CRYPTO_HMAC select CRYPTO_JITTERENTROPY select CRYPTO_RNG select CRYPTO_SHA512 + help + DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) -endif # if CRYPTO_DRBG_MENU + Enable this only if you need it for a FIPS 140 certification. + It's otherwise redundant with the kernel's regular RNG. config CRYPTO_JITTERENTROPY tristate "CPU Jitter Non-Deterministic RNG (Random Number Generator)" select CRYPTO_LIB_SHA3 select CRYPTO_RNG
Signature · 1 line
2.53.0
PATCH 15/38 crypto: testmgr - Add test for drbg_pr_hmac_sha512
In reply to Eric BiggersAdd a test for drbg_pr_hmac_sha512, which previously didn't have a test.
--- crypto/testmgr.c | 5 +- crypto/testmgr.h | 199 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 1 deletion(-)
crypto/testmgr.c +4 -1
@@ -4672,12 +4672,15 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_hmac_sha384", .test = alg_test_null, .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", - .test = alg_test_null, + .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 +199 -0
209 lines not on this page · raw message
Signature · 1 line
2.53.0
Re: [PATCH 15/38] crypto: testmgr - Add test for drbg_pr_hmac_sha512
Hi Eric,
Was there any particular reason for adding this test? I don't think there's any _explicit_ requirement for having tests for both non-PR and PR DRBG variants.
In fact, as part of this very comprehensive cleanup, maybe the PR variants of the DRBGs should be removed as well? Is anyone actually using those? PR variants are (were) registered before the non-PR variants, so non-PR was always used by default.
Kind regards,
Joachim
Quoted 243 lines · Eric Biggers
Add a test for
drbg_pr_hmac_sha512, which previously didn't have a test.Signed-off-by Eric Biggers <[email protected]>--- crypto/testmgr.c | 5 +- crypto/testmgr.h | 199 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 1 deletion(-)crypto/testmgr.c +4
-1@@ -4672,12 +4672,15 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_hmac_sha384", .test = alg_test_null, .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", - .test = alg_test_null, + .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 +199
-0@@ -23700,10 +23700,209 @@ static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { "\x36\x60\x3b\xca\x37\xc9\xee\x29", .perslen = 32, }, }; +static const struct drbg_testvec drbg_pr_hmac_sha512_tv_template[] = { +/* +* Borrowed from the first applicable test vector from ACVP: +* https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/prompt.json#L1161 +* https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/expectedResults.json#L271 +*/ + { +/* .entropy = ACVP entropyInput || nonce */ + .entropy ="\x9B\xE9\xB2\x87\xA3\x9A\x08\x44\x1D\x67\x82\x20" +"\xC9\x53\xFB\xEB\xA4\xB9\x0F\x44\x0B\x98\x33\x18" +"\xAC\x6E\x25\x4A\x85\x83\x2D\x26\x21\x9F\x93\x64" +"\xC8\x5A\x5F\x72\xDB\x88\x45\x96\x71\x41\xF4\xBF" +"\x6E\xA7\x98\x00\x9D\xD1\x0C\x2E\x4D\x7A\xE2\x03" +"\x0D\xE3\xCD\x62\xFE\xF3\x62\xBD\x12\x69\x92\x3D" +"\xBA\xAC\x15\x17\xC7\x80\x93\x8E\x72\x32\x2D\x52" +"\xE5\x2C\x19\x84\x5C\xA5\xCE\x5B\x98\x19\x1F\xF1" +"\x9F\x0C\x17\x04\xD0\x66\xF1\x9B\xFA\x7E\x2C\xB6" +"\x55\x68\xD4\x1B\xD6\x7A\x1D\x2C\xD4\x6D\x6E\x15" +"\xF7\x32\x23\x04\x05\x8C\xBB\xE6\x63\x6B\x80\x9B" +"\x9C\x69\x09\x8F\x5F\x02\xBF\x53\x42\x11\xB7\x80" +"\xAA\xD4\xE8\x54\x00\x83\x5C\x20\xA8\xB3\x6E\xD9" +"\xF5\x51\x9E\xB9\xD1\x6E\xC7\x0C\xE9\x7F\xF0\xBF" +"\xCE\x1D\xB0\x31\x8D\x16\xC9\x65\x0C\x18\x55\xA4" +"\x46\x8D\x54\x2B\x78\x69\x1B\x8C\x29\xD7\xAC\x0F" +"\x34\x4D\x69\x0B\x76\xC3\x98\x00\x78\x2F\xE2\x54" +"\xAF\xD5\x8A\xC3\x40\x97\xB1\xA2\x60\xD3\x07\x3B" +"\x7A\x3E\xD0\x82\x80\x68\xEE\xB0\x72\x5F\x07\x17" +"\xD9\x0A\xFC\xBD\xBA\xB6\x77\x4E\xC9\xCE\x6A\x48" +"\xEB\x9C\xF5\x18\x88\x1E\x6E\x3B\x65\x43\x16\x73" +"\x80\x53\xB7\xF0\x7E\xAB\x23\x19\x1E\x75\x60\x36" +"\xAF\x39\xC0\xCF\x0F\x6D\x7F\x90\xB2\x50\xD5\x37" +"\x58\x6D\x5C\x95\x78\x25\x8D\x3A\x40\xAB\xF6\x7B" +"\x85\x86\xBB\x48\x5E\x1C\x99\xC1\xD3\x4E\x85\xE5" +"\xB4\xE7\x61\xF3\x7D\x56\x1F\x77\xCF\x3C\x76\x3A" +"\xF4\x82\x36\xB7\x37\x33\x84\x34\xBA\x0E\xE2\xE1" +"\xAF\x0C\xD2\xAE\x97\x5C\x80\xD4\xD2\xFD\x37\x71" +"\xC8\x70\x04\x29\x8B\x44\xB9\xD7\xC9\x8F\xE7\x99" +"\x94\x9E\xFC\x49\x66\x24\xCB\x8B\x41\x40\x66\xC5" +"\xA4\x00\xD5\x3F\x68\xDD\xB5\xA5\x62\x96\x7C\xAC" +"\x63\x58\x95\x85\x99\x24\x21\x15\xD2\x76\xAF\x6D" , + .entropylen =384 , + .pers ="\xDD\x07\x10\x10\x17\x34\xD5\xBD\x43\xAF\x03\x79\xE4" +"\x64\x2C\x58\x06\xEA\xE0\x39\xDA\x42\x96\x16\x0B\xF9" +"\xB8\xCE\x57\x7D\x53\x67\xBF\xF8\x0C\x40\x02\xB2\x77" +"\x16\xD5\x23\x75\x9F\x6A\x42\x0E\xE8\xCC\xD0\x9F\x40" +"\x64\xE9\x3B\xE9\x48\x13\xC3\x8E\x4B\xAB\xE1\xB9\x4F" +"\x6D\xBB\xF2\x4C\xF8\x29\xA5\x2B\x44\x23\x15\x2C\xDE" +"\x2A\xCF\x88\x04\x7A\x38\x37\xA2\xD5\x7B\xEA\x59\x39" +"\x2C\x58\xA2\x5B\xF9\x39\xA2\x7E\x94\x11\x97\xEC\x47" +"\x08\xD6\xE2\x39\x65\x26\x43\x81\x3F\x1B\x31\xA6\xA4" +"\x1A\x5C\xCD\x02\xCC\x89\x38\x3F\x32\x7C\x0E\x7E\x88" +"\x3B\x6F\x60\x69\xEA\xBA\xAA\x1F\x53\x93\x70\xD7\x48" +"\x74\x91\x79\x5E\xD4\xB0\xD9\x82\x74\x12\xDE\xFE\xFB" +"\x51\x96\x66\x5C\x6A\x53\x11\xAD\x9A\xD4\xFA\x9D\xF0" +"\xE2\x7F\x26\x8F\x6F\xAC\x00\xC8\xDB\xCF\xA5\x8E\xE6" +"\x61\x8F\x36\xD6\x44\x5B\x07\xDA\x9C\x2A\x46\xE3\x03" +"\x1C\xD8\x11\x4F\x61\x1F\xEC\xBA\x12\x68\xB9\x4B\x57" +"\x39\x05\xD6\xEE\xC1\xAC\x3F\x6D\x6F\xE9\xBF\xEA\x36" +"\x1A\x8A\xAA\xF4\xE8\xE0\xDB\xC6\xE5\x06\x9F\xC9\x91" +"\x52\xCD\x53\xD0\x78\xF6\xC1\x7B\x75\x91\x85\x91\x13" +"\x26\xBE\xC9\x02\xDE\xB0\x19\xF2\x71" , + .perslen =256 , + + .entpra ="\xDB\xBA\x25\xC7\x02\x0D\x3D\x95\x9C\xEB\xF5\x42" +"\x52\x3A\x6B\xDA\xE8\xAF\xE9\x3D\x76\x2A\x9E\xB5" +"\xD7\xE7\x5D\xC9\xB8\x1F\x3A\xC2\x91\x95\x9D\xFD" +"\xE5\x48\x5F\x63\xD8\x84\x44\x82\x6A\x71\xF9\xDD" +"\xAF\x4B\xE2\x28\xB4\x30\xCF\x78\xB7\x0B\x0F\x61" +"\x71\x16\x1A\xE0\x6D\x5F\xB4\x4B\x17\x1A\x26\xCA" +"\xD8\x9D\x6D\x46\xA3\x56\xC0\xE7\x49\xCF\xE0\xD2" +"\xFF\xA8\x22\x45\xE0\xB4\x18\x0B\x13\x37\x01\x46" +"\xCB\xE7\xD8\x2A\x59\x43\xAD\x90\x1E\xE1\xD0\xD7" +"\x76\xB0\x2D\xCF\x17\x23\x99\x73\x5D\xE5\xC7\x46" +"\x8A\x0D\x8E\xC4\xAB\x45\xAC\xA8\x74\xE4\xF7\xD0" +"\x26\xD7\x0A\xE2\x43\x3D\xB8\xC7\xEE\xAD\x53\x6F" +"\x78\xC3\x51\xC0\xE0\x76\x2A\xC2\xB7\xFE\x02\x64" +"\x25\xF0\xCE\xD7\xA9\xBF\x85\xCA\x20\xA6\x93\x68" +"\xE3\x79\xE9\x88\xA8\x7F\x45\x8D\x71\xB4\xB4\x79" +"\x1C\x56\x68\xF9\xAE\x18\x76\xB9\x3F\xEE\x5B\x2C" +"\xC6\x61\x47\x34\x3B\xC5\x24\x2D\x3C\x6D\x16\x48" +"\x70\xD9\xDB\x2E\xB8\x42\x52\x81\x1C\x94\x39\xF0" +"\xF4\xC0\x8F\x44\xD3\xCF\xD5\xF9\xC1\x59\x61\x83" +"\xAE\xFD\xD0\xC4\x35\xD1\x0E\x55\x46\x5C\xBA\x3D" +"\x5C\x4A\x89\x15\xE8\x1D\x86\x28\xE5\xF5\x31\x0B" +"\x89\x59\xFE\x4A\xC3\x5D\xA5\x2A\x16\x37\x78\x41" +"\x58\x3A\x9E\xA3\xBD\x1F\xE6\x25\xCC\x18\x9E\xD2" +"\x1A\x99\x56\x66\x83\x78\xBB\x27\x3E\x28\xFE\xD4" +"\x74\xCB\x75\x2D\x82\x86\x55\xFB\x1C\xA4\xAF\x3F" +"\x84\x0A\xA0\xA1\x1C\x70\x34\x87\x2E\x73\x15\x38" +"\x8A\x27\xB1\x6C\x33\x95\xE5\x07" , + .entprb ="\x38\xF2\xC4\x8F\x4B\x9C\x2F\x03\x67\x8C\x8A\x47" +"\xE1\xF2\x18\xC5\xB8\x4C\x05\x77\x77\x15\xA8\x94" +"\x1F\x1F\x45\x6D\xD0\xEF\x60\x67\x63\x12\x5D\x38" +"\x89\x22\x76\xF5\xF2\xC4\xE1\x15\x26\x7E\x8F\x52" +"\x79\x1E\x96\x71\xCD\xE7\x32\x95\x2B\x4E\xB2\xC2" +"\x92\x21\xC7\x48\xA2\xB1\xC5\x71\x44\x91\xE4\x4F" +"\xBE\xD3\x5E\xA9\xAB\xD3\xE2\xD1\xE2\xD8\x8F\x98" +"\x38\x03\x18\x29\x84\xA2\xCA\x6E\x72\x34\xC9\x51" +"\x6D\x8C\xE8\x09\x50\x71\x2A\x08\xB7\xCF\x74\xE6" +"\x11\xB6\x38\xF5\xBC\x24\xF7\x5B\x73\x34\xD5\x8B" +"\xBB\x15\xE3\x6F\x9A\x9B\x1E\x32\xB9\x6F\x5F\xE3" +"\xC9\x9F\xF6\xD9\x33\x03\xCD\x0D\x8E\xD4\x3F\x67" +"\x11\x65\x0A\x90\x67\x83\xC1\xCC\x70\xB1\xA9\x46" +"\x4B\x5E\x0B\x84\xDC\x02\xBA\x50\x1D\x4A\x5B\xC7" +"\xB4\x5E\xDF\x35\x01\x45\x3D\x64\x5C\x2E\xCD\xA6" +"\x20\xFB\x35\x74\xC0\x7C\x2D\x24\x66\xAB\x38\x12" +"\x38\xCE\x52\xCB\x38\x9B\x95\xDE\x0C\x2A\x8C\x9D" +"\xF7\x81\x48\x9E\xD6\x10\xF1\x83\x71\x44\x53\x2F" +"\xCE\xF3\xEC\xB3\x29\x67\xF1\x41\xFC\xD6\xB6\x49" +"\xE3\x13\x74\x4D\xB2\x3E\xEA\x73\x2B\x03\x68\xAC" +"\x2F\x57\x8C\x58\xEC\x34\xE9\xEF\x18\x36\xDE\xAD" +"\xE9\x48\x1D\xF7\x9E\xB7\xA1\x60\x2E\x78\xF5\x62" +"\x68\xDD\xB8\x5B\x33\x6B\x66\xAD\xA1\xD5\xFB\x46" +"\x5E\x8F\xF8\x9D\x37\xE5\xC2\xD8\x76\xDC\x2B\x6A" +"\x99\x1E\xDF\x91\xB1\x0A\x81\x2A\x9D\xEB\xE7\xE4" +"\xD1\x21\xD4\xDA\x0E\x55\x8A\x14\xB2\xB6\x15\x7D" +"\x48\x52\x6A\xB0\xA2\x92\x4D\x50" , + .entprlen =320 , + .addtla ="\xC2\x89\x7C\x07\x46\x74\x02\x2C\xEA\xAD\xFD\x74" +"\x0C\x40\xEF\xA2\x95\x64\x6B\xC4\x2D\xED\xF4\x16" +"\x26\x25\x06\xB3\x36\x6B\xD8\x9A\x5F\xF4\x25\xC1" +"\xC3\x69\x3F\x7A\x19\xB7\x02\xA6\xCC\x3B\xA2\x4E" +"\x05\xA1\x1C\x7B\x2D\xAD\x44\xE7\x4A\x40\x71\x85" +"\xEF\x1C\xE4\xEC\x54\xCA\xB0\xAF\x8F\xF5\x43\xB1" +"\xE0\x99\x71\x71\xD4\x3E\x56\x97\xAA\xF5\xD0\x1A" +"\x58\x2D\x65\x0F\xA4\xB4\xB6\x07\x1B\x1F\x13\x8B" +"\x29\xD6\xE5\x23\xD3\x4D\x43\xD6\xBC\x74\xA8\x92" +"\xBD\xE9\x9B\x01\x47\x8C\xA5\x02\xA8\x0D\xC3\x3A" +"\xED\x83\xFD\xD2\xCB\xFF\x25\x89\x2C\x2F\x5B\x70" +"\x3F\x9E\x24\x50\xF8\x78\x28\x1B\x67\x52\x92\xA2" +"\x87\x81\x07\x40\xA9\x40\xBA\x84\x47\x25\xC1\xF7" +"\x9E\x3B\x4E\xE4\x8F\x10\xE5\x50\x8B\x22\x83\x4F" +"\xCD\x4E\x42\x63\x92\x0A\x5F\xAF\x7A\x9B\x0E\x1A" +"\xE3\xB4\x99\x11\x7F\xE6\x93\xC3\xED\xF1\x9F\x3A" , + .addtlb ="\x1E\x75\xB6\x70\x60\xFD\xE6\xD1\xC7\xA5\x74\xCF" +"\xA7\x50\x17\xAE\xDD\xC4\x6E\xC4\xE0\x15\xF0\x3B" +"\xF7\x1C\x46\x45\xEE\x60\x66\x48\x1D\x2C\x36\xCC" +"\x95\x3E\xB7\xEB\x1B\xFF\x8C\xC0\x78\x6D\x56\x3A" +"\xC7\x24\x18\x9E\x7C\xA1\x60\x54\x41\x4B\xAF\x18" +"\xE8\x02\xD1\x54\x65\xEC\x3D\xFD\x8B\xDF\xD2\xF5" +"\x62\xEA\x66\x41\x6A\x32\x87\xA6\x34\x2F\x48\xBF" +"\xB5\xCC\x35\x5A\x2A\xC1\xAB\x68\x34\x1A\xD6\x82" +"\x40\xF7\xF2\x00\x14\x8B\x69\x0F\xE4\xCD\x6B\xB1" +"\xFC\x8B\x16\xEC\xB4\xE3\x33\xBF\x84\x12\x4B\x58" +"\xED\x51\x88\xF5\xEF\xB6\xC3\xCE\x9B\x63\xCC\x80" +"\x1F\x3C\x8A\x67\xEE\xCD\xD2\x01\x25\x22\xAC\xB3" +"\xB6\x9B\x1F\xF8\xE8\x71\xE6\x0D\x78\x11\x3C\x9E" +"\xF2\x57\xDC\xB6\xCF\x90\xD3\xA8\x3E\xCD\x88\xD4" +"\xDC\x1C\x31\x6B\x1F\xC3\x6A\x29\xF0\x7B\x4C\xCC" +"\x6D\x92\x5E\x6F\x0C\x0B\x4D\xA7\x10\x66\x84\x1F" , + .addtllen =192 , + + .expected ="\xAA\x76\x91\xAE\x99\xCD\x8D\x83\x49\x9D\xC5\x51" +"\xA5\x95\xC6\x9D\xAD\x4B\x40\x2B\x5F\x8C\x30\x5D" +"\x1E\x89\x58\xD1\x8A\x86\xF9\x61\x2C\x45\x41\x8E" +"\xC5\xC6\x0E\x33\x7C\xFE\x91\x71\xC9\x53\x76\xD6" +"\xC2\x8D\x05\x09\xB8\x2A\x2B\x9B\x36\x1D\x31\xD7" +"\x50\x45\xB1\x08\x58\xC4\x99\x25\xEA\x2F\x18\xDB" +"\x34\x8A\x02\xD8\x38\xDD\x7B\x9E\x0E\xEF\x9C\x45" +"\xC7\x4F\x7E\x36\x3A\x90\x8B\x41\x51\x4A\x1B\xE9" +"\x8A\x61\xE9\xB5\x4E\xA5\xE2\xBD\x16\x59\x61\x0F" +"\x9C\x5A\x63\xA7\x87\x79\x5C\x0A\x16\xDF\x6D\x88" +"\x11\x25\x56\x8B\x5D\xA6\xF8\x4F\xB9\x01\x19\xAE" +"\x57\x3B\xC4\x06\xBB\xE7\xCB\xAF\xB3\x8D\xE2\x40" +"\xED\x42\x29\xB3\x0D\x64\x20\xF2\x66\x58\xB1\xDD" +"\x59\xB1\x39\x7C\xD9\xB2\x34\x08\x53\x9B\x3A\xB7" +"\x18\x35\xD0\x90\x7F\xB5\x30\xF2\x27\xA0\x90\x63" +"\x6F\xF2\x72\x49\xBF\xD0\xAE\x4A\xF4\xCA\xB3\x1A" +"\xAE\x7F\x93\xF3\xB9\x84\x99\x09\x50\xB9\xA0\x43" +"\x4F\x83\x33\x92\xA5\xC7\x25\x44\x6A\x74\xF4\xFA" +"\xBA\x60\x43\x13\x97\x53\x99\x98\xA3\x05\x02\xC1" +"\x03\xDF\x53\x76\x9E\x74\xE7\xA0\xB5\xD7\xA7\x87" +"\x1E\x00\x1D\x29\x47\x8F\x65\x4E\x0F\x76\xCA\xA9" +"\x2A\xC5\x05\x4F\xA6\xFE\x96\xC6\x81\xC0\x55\xFC" +"\x92\x89\xA6\x81\xF0\x37\xF1\x41\xA6\x88\x0B\x01" +"\xE0\xA5\x78\x4C\xF4\x61\xA7\x91\xD8\x4B\xE9\x2C" +"\xF0\x68\xEE\x46\x41\xD2\x74\xE5\x5F\x6F\x1F\xE6" +"\xBE\x5C\xB1\x3C\x60\x1A\xAA\xB9\x88\x3C\xB9\x1C" +"\xCD\x67\x78\x1F\x45\x18\xE7\x8B\xBD\xE4\x24\xDA" +"\xA8\x26\xD1\x03\xF1\xC7\x6B\x28\x62\xAB\x5C\xAB" +"\x98\xCA\xFB\xCB\x0B\x2D\x01\xD9\xC1\xA6\xFA\x91" +"\x71\x3D\x9B\x3B\x60\xEB\xD7\xA2\x61\xC1\x92\x60" +"\xB1\x02\x44\x0C\x97\x70\x77\x83\xF9\x35\xEA\x24" +"\x85\xF8\x0A\x32\xA2\xC7\x05\x40\x90\x83\x4F\x87" +"\x57\x66\xB5\xDE\xEE\xFF\x8B\x01\xBC\x96\xB0\xC5" +"\x29\xB6\xC1\xF0\x11\x31\x51\x11\xB0\xC2\x0F\x08" +"\xCF\x09\x69\x74\xE1\x0D\x6C\x0A\x10\xD0\x73\xF0" +"\x8E\xDC\x5F\xB1\xBD\x47\x8A\xA7\x90\xB3\x08\x86" +"\xD2\xE4\x58\xE5\x68\x33\x67\x3B\x37\xF1\x28\x28" +"\x59\x91\xB5\x5F\x8D\x84\x54\xCE\x18\x76\xE3\x5C" +"\x55\x37\x8E\x10\x34\x9B\x6E\x1F\x73\x88\x31\xBF" +"\x0D\x5C\xED\x7A\xBC\xF2\xCE\x7A\x2E\x2E\xE7\x04" +"\xE7\xF2\x8F\x33\xCC\x06\x77\x96\xBB\xA8\x65\x03" +"\x26\x79\xC0\xF0\x52\x3B\xD4\xF2\x5D\x00\xE4\x80" +"\x7F\x78\xC0\x45\x29\x55\xCA\x63" , + .expectedlen =512 , + } +}; +/* Test vector obtained during NIST ACVP testing */ static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { { .entropy = (unsigned char *)"\xDF\xB0\xF2\x18\xF0\x78\x07\x01\x29\xA4\x29\x26"
Re: [PATCH 15/38] crypto: testmgr - Add test for drbg_pr_hmac_sha512
Quoted 5 lines · Joachim Vandersmissen
Hi Eric,
Was there any particular reason for adding this test? I don't think there's any _explicit_ requirement for having tests for both non-PR and PR DRBG variants.
Well, *if* predictionResistance=true continues to supported, then this test is needed, considering that drbg_pr_hmac_sha256 and its test was removed. Code always should be tested. (Also, considering FIPS, the guidance I've gotten from a FIPS lab in the past is that predictionResistance=true has to be tested if it's supported.)
Quoted 4 lines
In fact, as part of this very comprehensive cleanup, maybe the PR variants of the DRBGs should be removed as well? Is anyone actually using those? PR variants are (were) registered before the non-PR variants, so non-PR was always used by default.
But yes, I think you're right that we should just go ahead and remove support for predictionResistance=true too. I was a bit on the fence about removing something that's "more" secure and also has a relatively straightforward implementation. But since it's not the default, it doesn't make much sense to use it, this test would have to be added, and it's not required for FIPS certifications either (in fact it seems to just make them a bit harder), it does seem like the right choice.
- Eric
PATCH 16/38 crypto: testmgr - Update test for drbg_nopr_hmac_sha512
In reply to Eric BiggersSynchronize the drbg_nopr_hmac_sha512 test vector with the first test vector from the latest ACVP json files, so that both of the DRBG test vectors are pulled from a consistent source.
Note that the new test vector has a nonempty personalization string. That should be helpful as well: Some FIPS labs require this, due to their interpretation of SP800-90A 11.3.2 which says that a "representative" value of the personalization string must be tested.
It also now does an explicit reseed, which makes it clearer that the requirement to test "Reseed" is met, without having to interpret the additional input processing as covering that.
--- crypto/testmgr.c | 13 ++- crypto/testmgr.h | 249 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 215 insertions(+), 47 deletions(-)
crypto/testmgr.c +12 -1
@@ -3502,14 +3502,25 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, }crypto_rng_set_entropy (drng, test->entropy, test->entropylen); ret =crypto_rng_reset (drng, test->pers, test->perslen);if (ret) { -printk (KERN_ERR "alg: drbg: Failed to reset rng\n" ); +printk (KERN_ERR "alg: drbg: Failed to instantiate rng\n" ); goto outbuf; } +if (test->ent_reseed_len) { +crypto_rng_set_entropy (drng, test->ent_reseed, + test->ent_reseed_len); + ret =crypto_rng_reset (drng, test->addtl_reseed, + test->addtl_reseed_len); +if (ret) { +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 ) {
crypto/testmgr.h +203 -46
279 lines not on this page · raw message
Signature · 1 line
2.53.0
PATCH 17/38 crypto: drbg - Remove support for HMAC-SHA256 and HMAC-SHA384
In reply to Eric BiggersRemove support for the HMAC-SHA256 and HMAC-SHA384 variants of HMAC_DRBG, leaving only the HMAC-SHA512 variant of HMAC_DRBG.
HMAC-SHA512 is already the default. The default did used to be HMAC-SHA256, but several years ago it was upgraded to HMAC-SHA512 "to support compliance with SP800-90B and SP800-90C". Given that the point of crypto/drbg.c is compliance with those standards, and there's also no technical reason to prefer HMAC-SHA384 in this situation even if acceptable, there's really no point in offering anything else.
Note: now that only HMAC-SHA512 remains, a lot of unnecessary abstractions can be removed. A later commit will do that. This commit just straightforwardly removes the HMAC-SHA256 and HMAC-SHA384 code.
--- crypto/drbg.c | 22 +--- crypto/testmgr.c | 27 ----- crypto/testmgr.h | 280 ----------------------------------------------- 3 files changed, 2 insertions(+), 327 deletions(-)
crypto/drbg.c +2 -20
@@ -1,11 +1,9 @@/* * DRBG: Deterministic Random Bits Generator -* Based on NIST Recommended DRBG from NIST SP800-90A with the following -* properties: -* * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores -* * with and without prediction resistance +* Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A, +* both with and without prediction resistance * * Copyright Stephan Mueller <[email protected]>, 2014 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions
@@ -213,22 +211,10 @@ enum drbg_prefixes {* * Thus, the favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { { - .flags =DRBG_HMAC |DRBG_STRENGTH256 , - .statelen =48 ,/* block length of cipher */ - .blocklen_bytes =48 , - .cra_name ="hmac_sha384" , - .backend_cra_name ="hmac(sha384)" , - }, { - .flags =DRBG_HMAC |DRBG_STRENGTH256 , - .statelen =32 ,/* block length of cipher */ - .blocklen_bytes =32 , - .cra_name ="hmac_sha256" , - .backend_cra_name ="hmac(sha256)" , - }, { .flags =DRBG_HMAC |DRBG_STRENGTH256 , .statelen =64 ,/* block length of cipher */ .blocklen_bytes =64 , .cra_name ="hmac_sha512" , .backend_cra_name ="hmac(sha512)" ,
@@ -274,14 +260,10 @@ static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg,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" ); -MODULE_ALIAS_CRYPTO ("drbg_pr_hmac_sha384" ); -MODULE_ALIAS_CRYPTO ("drbg_nopr_hmac_sha384" ); -MODULE_ALIAS_CRYPTO ("drbg_pr_hmac_sha256" ); -MODULE_ALIAS_CRYPTO ("drbg_nopr_hmac_sha256" );/* 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) {
crypto/testmgr.c +0 -27
@@ -4647,44 +4647,17 @@ static const struct alg_test_desc alg_test_descs[] = { .kpp = __VECS(dh_tv_template) } }, { .alg = "digest_null", .test = alg_test_null, - }, { - .alg = "drbg_nopr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_hmac_sha256_tv_template) - } - }, { -/* -* There is no need to specifically test the DRBG with every -* backend cipher -- covered by drbg_nopr_hmac_sha512 test -*/ - .alg = "drbg_nopr_hmac_sha384", - .test = alg_test_null, - .fips_allowed = 1 }, { .alg = "drbg_nopr_hmac_sha512", .test = alg_test_drbg, .fips_allowed = 1, .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_pr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_hmac_sha256_tv_template) - } - }, { -/* covered by drbg_pr_hmac_sha256 test */ - .alg = "drbg_pr_hmac_sha384", - .test = alg_test_null, - .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", .test = alg_test_drbg, .fips_allowed = 1, .suite = {
crypto/testmgr.h +0 -280
290 lines not on this page · raw message
Signature · 1 line
2.53.0
PATCH 18/38 crypto: drbg - Simplify algorithm registration
In reply to Eric BiggersNow that "drbg_pr_hmac_sha512" and "drbg_nopr_hmac_sha512" are the only crypto_rng algorithms left in crypto/drbg.c, simplify the algorithm registration logic to register these more directly without relying on the drbg_cores[] array (which will be removed).
--- crypto/drbg.c | 100 ++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 65 deletions(-)
crypto/drbg.c +35 -65
@@ -1143,90 +1143,60 @@ static inline int __init drbg_healthcheck_sanity(void)kfree (drbg);return rc; } -static struct rng_alg drbg_algs[22 ]; - -/* -* Fill the array drbg_algs used to register the different DRBGs -* with the kernel crypto API. To fill the array, the information -* from drbg_cores[] is used. -*/ -static inline void __init drbg_fill_array (struct rng_alg *alg, -const struct drbg_core *core,int pr) -{ -int pos =0 ; -static int priority =200 ; - -memcpy (alg->base.cra_name,"stdrng" ,6 ); -if (pr) { -memcpy (alg->base.cra_driver_name,"drbg_pr_" ,8 ); - pos =8 ; - }else { -memcpy (alg->base.cra_driver_name,"drbg_nopr_" ,10 ); - pos =10 ; - } -memcpy (alg->base.cra_driver_name + pos, core->cra_name, -strlen (core->cra_name)); - - alg->base.cra_priority = priority; - priority++; -/* -* If FIPS mode enabled, the selected DRBG shall have the -* highest cra_priority over other stdrng instances to ensure -* it is selected. -*/ -if (fips_enabled) - alg->base.cra_priority +=2000 ; - - alg->base.cra_ctxsize =sizeof (struct drbg_state ); - alg->base.cra_module =THIS_MODULE ; - alg->base.cra_init = drbg_kcapi_init; - alg->base.cra_exit = drbg_kcapi_cleanup; - alg->generate = drbg_kcapi_random; - alg->seed = drbg_kcapi_seed; - alg->set_ent = drbg_kcapi_set_entropy; - alg->seedsize =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, + .generate = drbg_kcapi_random, + .base.cra_exit = drbg_kcapi_cleanup, + }, + { + .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_random, + .base.cra_exit = drbg_kcapi_cleanup, + }, +};static int __init drbg_init (void ) { -unsigned int i =0 ;/* pointer to drbg_algs */ -unsigned int j =0 ;/* pointer to drbg_cores */ int ret; ret =drbg_healthcheck_sanity ();if (ret)return ret; -if (ARRAY_SIZE (drbg_cores) *2 >ARRAY_SIZE (drbg_algs)) { -pr_info ("DRBG: Cannot register all DRBG types" -"(slots needed: %zu, slots available: %zu)\n" , -ARRAY_SIZE (drbg_cores) *2 ,ARRAY_SIZE (drbg_algs)); -return -EFAULT ; - } -/* -* each DRBG definition can be used with PR and without PR, thus -* we instantiate each DRBG in drbg_cores[] twice. -* -* As the order of placing them into the drbg_algs array matters -* (the later DRBGs receive a higher cra_priority) we register the -* prediction resistance DRBGs first as the should not be too -* interesting. +* In FIPS mode, boost the algorithm priorities to ensure that when +* users request "stdrng", they really get an algorithm from here. */ -for (j =0 ;ARRAY_SIZE (drbg_cores) > j; j++, i++) -drbg_fill_array (&drbg_algs[i], &drbg_cores[j],1 ); -for (j =0 ;ARRAY_SIZE (drbg_cores) > j; j++, i++) -drbg_fill_array (&drbg_algs[i], &drbg_cores[j],0 ); -return crypto_register_rngs (drbg_algs, (ARRAY_SIZE (drbg_cores) *2 )); +if (fips_enabled) { +for (size_t i =0 ; i <ARRAY_SIZE (drbg_algs); i++) + drbg_algs[i].base.cra_priority +=2000 ; + } + +return crypto_register_rngs (drbg_algs,ARRAY_SIZE (drbg_algs)); } static void __exit drbg_exit(void) { -crypto_unregister_rngs (drbg_algs, (ARRAY_SIZE (drbg_cores) *2 )); +crypto_unregister_rngs (drbg_algs,ARRAY_SIZE (drbg_algs)); }module_init (drbg_init);module_exit (drbg_exit);MODULE_LICENSE ("GPL" );
Signature · 1 line
2.53.0
PATCH 19/38 crypto: drbg - De-virtualize drbg_state_ops
In reply to Eric BiggersNow that there's only one set of state operations, use direct calls to those operations.
No change in behavior. In particular, drbg_alloc_state() doesn't change behavior, because the only remaining drbg_core uses HMAC_DRBG. drbg_uninstantiate() doesn't change behavior, because a NULL d_ops implied NULL priv_data which makes a drbg_fini_hash_kernel() a no-op.
--- crypto/drbg.c | 50 ++++++-------------------------------------------- 1 file changed, 6 insertions(+), 44 deletions(-)
crypto/drbg.c +6 -44
@@ -109,21 +109,10 @@ struct drbg_core {char cra_name[CRYPTO_MAX_ALG_NAME ];/* mapping to kernel crypto API */ /* kernel crypto API backend cipher name */ char backend_cra_name[CRYPTO_MAX_ALG_NAME ]; }; -struct drbg_state_ops { -int (*update)(struct drbg_state *drbg,struct list_head *seed, -int reseed); -int (*generate)(struct drbg_state *drbg, -unsigned char *buf,unsigned int buflen, -struct list_head *addtl); -int (*crypto_init)(struct drbg_state *drbg); -int (*crypto_fini)(struct drbg_state *drbg); - -}; -enum drbg_seed_state {DRBG_SEED_STATE_UNSEEDED ,DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ DRBG_SEED_STATE_FULL , };
@@ -141,11 +130,10 @@ struct drbg_state {enum drbg_seed_state seeded;/* DRBG fully seeded? */ unsigned long last_seed_time;bool pr;/* Prediction resistance enabled? */ struct crypto_rng *jent; -const struct drbg_state_ops *d_ops;const struct drbg_core *core;struct drbg_string test_data; };static inline __u8 drbg_statelen (struct drbg_state *drbg)
@@ -248,11 +236,11 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags)return 32 ; } }/****************************************************************** -* HMAC DRBG callback functions +* 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,
@@ -358,25 +346,14 @@ static int drbg_hmac_generate(struct drbg_state *drbg,return ret;return len; } -static const struct drbg_state_ops drbg_hmac_ops = { - .update = drbg_hmac_update, - .generate = drbg_hmac_generate, - .crypto_init = drbg_init_hash_kernel, - .crypto_fini = drbg_fini_hash_kernel, -}; - -/****************************************************************** -* Functions common for DRBG implementations -******************************************************************/ -static inline int __drbg_seed (struct drbg_state *drbg,struct list_head *seed,int reseed,enum drbg_seed_state new_seed_state) { -int ret = drbg->d_ops->update (drbg, seed, reseed); +int ret =drbg_hmac_update (drbg, seed, reseed);if (ret)return ret; drbg->seeded = new_seed_state;
@@ -576,11 +553,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) drbg->V =NULL ;kfree_sensitive (drbg->Cbuf); drbg->Cbuf =NULL ; drbg->C =NULL ; drbg->reseed_ctr =0 ; - drbg->d_ops =NULL ; drbg->core =NULL ; }/* * Allocate all sub-structures for a DRBG state.
@@ -588,20 +564,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)*/ static inline int drbg_alloc_state (struct drbg_state *drbg) {int ret = -ENOMEM ; -switch (drbg->core->flags &DRBG_TYPE_MASK ) { -case DRBG_HMAC : - drbg->d_ops = &drbg_hmac_ops; -break ; -default : - ret = -EOPNOTSUPP ; - goto err; - } - - ret = drbg->d_ops->crypto_init (drbg); + ret =drbg_init_hash_kernel (drbg);if (ret <0 ) goto err; drbg->Vbuf =kmalloc (drbg_statelen (drbg) + ret,GFP_KERNEL );if (!drbg->Vbuf) {
@@ -617,20 +584,16 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) drbg->C =PTR_ALIGN (drbg->Cbuf, ret +1 );return 0 ; fini: - drbg->d_ops->crypto_fini (drbg); +drbg_fini_hash_kernel (drbg); err:drbg_dealloc_state (drbg);return ret; } -/************************************************************************* -* DRBG interface functions -*************************************************************************/ -/* * DRBG generate function as required by SP800-90A - this function * generates random numbers * * @drbg DRBG state handle
@@ -712,11 +675,11 @@ static int drbg_generate(struct drbg_state *drbg, }if (addtl &&0 < addtl->len)list_add_tail (&addtl->list, &addtllist);/* 9.3.1 step 8 and 10 */ - len = drbg->d_ops->generate (drbg, buf, buflen, &addtllist); + len =drbg_hmac_generate (drbg, buf, buflen, &addtllist);/* 10.1.2.5 step 7 */ drbg->reseed_ctr++;if (0 >= len) goto err;
@@ -877,12 +840,11 @@ static int drbg_uninstantiate(struct drbg_state *drbg) {if (!IS_ERR_OR_NULL (drbg->jent))crypto_free_rng (drbg->jent); drbg->jent =NULL ; -if (drbg->d_ops) - drbg->d_ops->crypto_fini (drbg); +drbg_fini_hash_kernel (drbg);drbg_dealloc_state (drbg);/* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0 ; }
Signature · 1 line
2.53.0
PATCH 20/38 crypto: drbg - Move fixed values into constants
In reply to Eric BiggersSince only one drbg_core remains, the state length, block length, and security strength are now fixed values. Moreover, the maximum request length, maximum additional data length, and maximum number of requests were all already fixed values.
Simplify the code by just using #defines for all these fixed values.
In drbg_seed_from_random(), take advantage of the constant to define the array size. Remove assertions that are no longer useful.
In the case of drbg_blocklen() and drbg_statelen(), replace these with a single value DRBG_STATE_LEN, as for HMAC_DRBG they are the same thing.
--- crypto/drbg.c | 183 +++++++++++++++++--------------------------------- 1 file changed, 61 insertions(+), 122 deletions(-)
crypto/drbg.c +61 -122
@@ -89,25 +89,22 @@*/ #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> #include <linux/jiffies.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/string_choices.h> #include <linux/unaligned.h> struct drbg_state ; -typedef uint32_t drbg_flag_t ;struct drbg_core { -drbg_flag_t flags;/* flags for the cipher */ -__u8 statelen;/* maximum state length */ -__u8 blocklen_bytes;/* block size of output in bytes */ char cra_name[CRYPTO_MAX_ALG_NAME ];/* mapping to kernel crypto API */ /* kernel crypto API backend cipher name */ char backend_cra_name[CRYPTO_MAX_ALG_NAME ]; };
@@ -115,10 +112,36 @@ enum drbg_seed_state {DRBG_SEED_STATE_UNSEEDED ,DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ DRBG_SEED_STATE_FULL, }; +/* 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 (1 << 20) + +/* +* 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 (U32_MAX - 1) +struct drbg_state {struct mutex drbg_mutex;/* lock around DRBG */ unsigned char *V;/* internal state -- 10.1.2.1 1a */ unsigned char *Vbuf;unsigned char *C;/* current key -- 10.1.2.1 1b */
@@ -134,57 +157,10 @@ struct drbg_state {struct crypto_rng *jent;const struct drbg_core *core;struct drbg_string test_data; }; -static inline __u8 drbg_statelen (struct drbg_state *drbg) -{ -if (drbg && drbg->core) -return drbg->core->statelen; -return 0 ; -} - -static inline __u8 drbg_blocklen (struct drbg_state *drbg) -{ -if (drbg && drbg->core) -return drbg->core->blocklen_bytes; -return 0 ; -} - -static inline size_t drbg_max_request_bytes (struct drbg_state *drbg) -{ -/* SP800-90A requires the limit 2**19 bits, but we return bytes */ -return (1 <<16 ); -} - -/* -* SP800-90A allows implementations to support additional info / personalization -* strings of up to 2**35 bits. Implementations can have a smaller maximum. We -* use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a -* size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. -*/ -static inline size_t drbg_max_addtl (struct drbg_state *drbg) -{ -return U32_MAX -1 ; -} - -static inline size_t drbg_max_requests (struct drbg_state *drbg) -{ -/* SP800-90A requires 2**48 maximum requests before reseeding */ -return (1 <<20 ); -} - -/* DRBG type flags */ -#define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_TYPE_MASK DRBG_HMAC -/* DRBG strength flags */ -#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) -#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) -#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) -#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ - DRBG_STRENGTH256) -enum drbg_prefixes {DRBG_PREFIX0 =0x00 ,DRBG_PREFIX1 , };
@@ -199,46 +175,17 @@ enum drbg_prefixes {* * Thus, the favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { { - .flags =DRBG_HMAC |DRBG_STRENGTH256 , - .statelen =64 ,/* block length of cipher */ - .blocklen_bytes =64 , .cra_name ="hmac_sha512" , .backend_cra_name ="hmac(sha512)" , }, };static int drbg_uninstantiate (struct drbg_state *drbg); -/****************************************************************** -* Generic helper functions -******************************************************************/ - -/* -* Return strength of DRBG according to SP800-90A section 8.4 -* -* @flags DRBG flags reference -* -* Return: normalized strength in *bytes* value or 32 as default -* to counter programming errors -*/ -static inline unsigned short drbg_sec_strength (drbg_flag_t flags) -{ -switch (flags &DRBG_STRENGTH_MASK ) { -case DRBG_STRENGTH128 : -return 16 ; -case DRBG_STRENGTH192 : -return 24 ; -case DRBG_STRENGTH256 : -return 32 ; -default : -return 32 ; - } -} -/****************************************************************** * HMAC DRBG functions ******************************************************************/ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,
@@ -261,24 +208,24 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,LIST_HEAD (seedlist);LIST_HEAD (vdatalist);if (!reseed) {/* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ -memset (drbg->V,1 ,drbg_statelen (drbg)); +memset (drbg->V,1 ,DRBG_STATE_LEN );drbg_kcapi_hmacsetkey (drbg, drbg->C); } -drbg_string_fill (&seed1, drbg->V,drbg_statelen (drbg)); +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_statelen (drbg)); +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)
@@ -319,20 +266,20 @@ static int drbg_hmac_generate(struct drbg_state *drbg, ret =drbg_hmac_update (drbg, addtl,1 );if (ret)return ret; } -drbg_string_fill (&data, drbg->V,drbg_statelen (drbg)); +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; - outlen = (drbg_blocklen (drbg) < (buflen - len)) ? -drbg_blocklen (drbg) : (buflen - len); + outlen = (DRBG_STATE_LEN < (buflen - len)) ? +DRBG_STATE_LEN : (buflen - len);/* 10.1.2.5 step 4.2 */ memcpy (buf + len, drbg->V, outlen); len += outlen; }
@@ -375,11 +322,11 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,case DRBG_SEED_STATE_FULL :/* * Seed source has become fully initialized, frequent * reseeds no longer required. */ - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ;break ; }return ret; }
@@ -387,25 +334,21 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,static int drbg_seed_from_random (struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) {struct drbg_string data;LIST_HEAD (seedlist); -unsigned int entropylen =drbg_sec_strength (drbg->core->flags); -unsigned char entropy[32 ]; +unsigned char entropy[DRBG_SEC_STRENGTH ];int ret; -BUG_ON (!entropylen); -BUG_ON (entropylen >sizeof (entropy)); - -drbg_string_fill (&data, entropy, entropylen); +drbg_string_fill (&data, entropy,DRBG_SEC_STRENGTH );list_add_tail (&data.list, &seedlist); -get_random_bytes (entropy, entropylen); +get_random_bytes (entropy,DRBG_SEC_STRENGTH ); ret =__drbg_seed (drbg, &seedlist, true,DRBG_SEED_STATE_FULL ); -memzero_explicit (entropy, entropylen); +memzero_explicit (entropy,DRBG_SEC_STRENGTH );return ret; }static bool drbg_nopr_reseed_interval_elapsed (struct drbg_state *drbg) {
@@ -442,17 +385,17 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, bool reseed) __must_hold(&drbg->drbg_mutex) {int ret;unsigned char entropy[((32 +16 ) *2 )]; -unsigned int entropylen =drbg_sec_strength (drbg->core->flags); +unsigned int entropylen;struct drbg_string data1;LIST_HEAD (seedlist);enum drbg_seed_state new_seed_state =DRBG_SEED_STATE_FULL ;/* 9.1 / 9.2 / 9.3.1 step 3 */ -if (pers && pers->len > (drbg_max_addtl (drbg))) { +if (pers && pers->len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: personalization string too long %zu\n" , pers->len);return -EINVAL ; }
@@ -467,13 +410,14 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,* 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. */ -BUG_ON (!entropylen);if (!reseed) - entropylen = ((entropylen +1 ) /2 ) *3 ; + entropylen = ((DRBG_SEC_STRENGTH +1 ) /2 ) *3 ; +else + entropylen =DRBG_SEC_STRENGTH ;BUG_ON ((entropylen *2 ) >sizeof (entropy));/* Get seed from in-kernel /dev/urandom */ if (!rng_is_initialized ()) new_seed_state =DRBG_SEED_STATE_PARTIAL ;
@@ -529,18 +473,18 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,list_add_tail (&pers->list, &seedlist);pr_devel ("DRBG: using personalization string\n" ); }if (!reseed) { -memset (drbg->V,0 ,drbg_statelen (drbg)); -memset (drbg->C,0 ,drbg_statelen (drbg)); +memset (drbg->V,0 ,DRBG_STATE_LEN ); +memset (drbg->C,0 ,DRBG_STATE_LEN ); } ret =__drbg_seed (drbg, &seedlist, reseed, new_seed_state); out: -memzero_explicit (entropy, entropylen *2 ); +memzero_explicit (entropy,sizeof (entropy));return ret; }/* Free all substructures in a DRBG state without the DRBG state structure */
@@ -568,17 +512,17 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) ret =drbg_init_hash_kernel (drbg);if (ret <0 ) goto err; - drbg->Vbuf =kmalloc (drbg_statelen (drbg) + ret,GFP_KERNEL ); + drbg->Vbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL );if (!drbg->Vbuf) { ret = -ENOMEM ; goto fini; } drbg->V =PTR_ALIGN (drbg->Vbuf, ret +1 ); - drbg->Cbuf =kmalloc (drbg_statelen (drbg) + ret,GFP_KERNEL ); + drbg->Cbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL );if (!drbg->Cbuf) { ret = -ENOMEM ; goto fini; } drbg->C =PTR_ALIGN (drbg->Cbuf, ret +1 );
@@ -628,24 +572,23 @@ static int drbg_generate(struct drbg_state *drbg,pr_devel ("DRBG: wrong format of additional information\n" );return -EINVAL ; }/* 9.3.1 step 2 */ - len = -EINVAL ; -if (buflen > (drbg_max_request_bytes (drbg))) { +if (buflen >DRBG_MAX_REQUEST_BYTES ) {pr_devel ("DRBG: requested random numbers too large %u\n" , buflen); - goto err; +return -EINVAL ; }/* 9.3.1 step 3 is implicit with the chosen DRBG */ /* 9.3.1 step 4 */ -if (addtl && addtl->len > (drbg_max_addtl (drbg))) { +if (addtl && addtl->len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: additional information string too long %zu\n" , addtl->len); - goto err; +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
@@ -721,12 +664,12 @@ static int drbg_generate_long(struct drbg_state *drbg,unsigned int len =0 ;unsigned int slice =0 ; do { int err = 0; unsigned int chunk = 0; - slice = ((buflen - len) / drbg_max_request_bytes(drbg)); - chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len); + slice = (buflen - len) / DRBG_MAX_REQUEST_BYTES; + chunk = slice ? DRBG_MAX_REQUEST_BYTES : (buflen - len); mutex_lock(&drbg->drbg_mutex); err = drbg_generate(drbg, buf + len, chunk, addtl); mutex_unlock(&drbg->drbg_mutex); if (0 > err) return err;
@@ -783,22 +726,21 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,/* 9.1 step 1 is implicit with the selected DRBG type */ /* * 9.1 step 2 is implicit as caller can select prediction resistance -* and the flag is copied into drbg->flags -- * all DRBG types support prediction resistance */ -/* 9.1 step 4 is implicit in drbg_sec_strength */ +/* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ if (!drbg->core) { drbg->core = &drbg_cores[coreref]; drbg->pr = pr; drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; drbg->last_seed_time =0 ; - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ; ret =drbg_alloc_state (drbg);if (ret) goto unlock;
@@ -882,11 +824,11 @@ static int drbg_init_hash_kernel(struct drbg_state *drbg)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_blocklen (drbg) !=crypto_shash_digestsize (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 ;
@@ -912,11 +854,11 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg)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_statelen (drbg)); +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) {
@@ -1058,11 +1000,10 @@ static inline int __init drbg_healthcheck_sanity(void)int ret;int rc = -EFAULT ;bool pr = false;int coreref =0 ;struct drbg_string addtl; -size_t max_addtllen, max_request_bytes;/* only perform test in FIPS mode */ if (!fips_enabled)return 0 ;
@@ -1072,28 +1013,26 @@ static inline int __init drbg_healthcheck_sanity(void)if (!drbg)return -ENOMEM ;guard (mutex_init)(&drbg->drbg_mutex); drbg->core = &drbg_cores[coreref]; - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ;/* * 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. */ - max_addtllen =drbg_max_addtl (drbg); - max_request_bytes =drbg_max_request_bytes (drbg); -drbg_string_fill (&addtl, buf, max_addtllen +1 ); +drbg_string_fill (&addtl, buf,DRBG_MAX_ADDTL +1 );/* overflow addtllen with additional info string */ ret =drbg_generate (drbg, buf,OUTBUFLEN , &addtl);BUG_ON (ret ==0 );/* overflow max_bits */ - ret =drbg_generate (drbg, buf, max_request_bytes +1 ,NULL ); + ret =drbg_generate (drbg, buf,DRBG_MAX_REQUEST_BYTES +1 ,NULL );BUG_ON (ret ==0 );/* overflow max addtllen with personalization string */ ret =drbg_seed (drbg, &addtl, false);BUG_ON (0 == ret);
Signature · 1 line
2.53.0
Re: [PATCH 20/38] crypto: drbg - Move fixed values into constants
Hi Eric,
If possible, I suggest using "DRBG_MAX_ADDTL_BYTES" for consistency with DRBG_MAX_REQUEST_BYTES and avoiding any possible confusion in the future.
Kind regards,
Joachim
Quoted 504 lines · Eric Biggers
Since only one
drbg_coreremains, the state length, block length, and security strength are now fixed values. Moreover, the maximum request length, maximum additional data length, and maximum number of requests were all already fixed values.Simplify the code by just using #defines for all these fixed values.
In
drbg_seed_from_random(), take advantage of the constant to define the array size. Remove assertions that are no longer useful.In the case of
drbg_blocklen()anddrbg_statelen(), replace these with a single valueDRBG_STATE_LEN, as forHMAC_DRBGthey are the same thing.Signed-off-by Eric Biggers <[email protected]>--- crypto/drbg.c | 183 +++++++++++++++++--------------------------------- 1 file changed, 61 insertions(+), 122 deletions(-)crypto/drbg.c +61
-122@@ -89,25 +89,22 @@*/ #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> #include <linux/jiffies.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/string_choices.h> #include <linux/unaligned.h> struct drbg_state ; -typedef uint32_t drbg_flag_t ;struct drbg_core { -drbg_flag_t flags;/* flags for the cipher */ -__u8 statelen;/* maximum state length */ -__u8 blocklen_bytes;/* block size of output in bytes */ char cra_name[CRYPTO_MAX_ALG_NAME ];/* mapping to kernel crypto API */ /* kernel crypto API backend cipher name */ char backend_cra_name[CRYPTO_MAX_ALG_NAME ]; };@@ -115,10 +112,36 @@ enum drbg_seed_state {DRBG_SEED_STATE_UNSEEDED ,DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ DRBG_SEED_STATE_FULL, }; +/* 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 (1 << 20) + +/* +* 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 (U32_MAX - 1) +struct drbg_state {struct mutex drbg_mutex;/* lock around DRBG */ unsigned char *V;/* internal state -- 10.1.2.1 1a */ unsigned char *Vbuf;unsigned char *C;/* current key -- 10.1.2.1 1b */ @@ -134,57 +157,10 @@ struct drbg_state {struct crypto_rng *jent;const struct drbg_core *core;struct drbg_string test_data; }; -static inline __u8 drbg_statelen (struct drbg_state *drbg) -{ -if (drbg && drbg->core) -return drbg->core->statelen; -return 0 ; -} - -static inline __u8 drbg_blocklen (struct drbg_state *drbg) -{ -if (drbg && drbg->core) -return drbg->core->blocklen_bytes; -return 0 ; -} - -static inline size_t drbg_max_request_bytes (struct drbg_state *drbg) -{ -/* SP800-90A requires the limit 2**19 bits, but we return bytes */ -return (1 <<16 ); -} - -/* -* SP800-90A allows implementations to support additional info / personalization -* strings of up to 2**35 bits. Implementations can have a smaller maximum. We -* use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a -* size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. -*/ -static inline size_t drbg_max_addtl (struct drbg_state *drbg) -{ -return U32_MAX -1 ; -} - -static inline size_t drbg_max_requests (struct drbg_state *drbg) -{ -/* SP800-90A requires 2**48 maximum requests before reseeding */ -return (1 <<20 ); -} - -/* DRBG type flags */ -#define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_TYPE_MASK DRBG_HMAC -/* DRBG strength flags */ -#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) -#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) -#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) -#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ - DRBG_STRENGTH256) -enum drbg_prefixes {DRBG_PREFIX0 =0x00 ,DRBG_PREFIX1 , };@@ -199,46 +175,17 @@ enum drbg_prefixes {* * Thus, the favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { { - .flags =DRBG_HMAC |DRBG_STRENGTH256 , - .statelen =64 ,/* block length of cipher */ - .blocklen_bytes =64 , .cra_name ="hmac_sha512" , .backend_cra_name ="hmac(sha512)" , }, };static int drbg_uninstantiate (struct drbg_state *drbg); -/****************************************************************** -* Generic helper functions -******************************************************************/ - -/* -* Return strength of DRBG according to SP800-90A section 8.4 -* -* @flags DRBG flags reference -* -* Return: normalized strength in *bytes* value or 32 as default -* to counter programming errors -*/ -static inline unsigned short drbg_sec_strength (drbg_flag_t flags) -{ -switch (flags &DRBG_STRENGTH_MASK ) { -case DRBG_STRENGTH128 : -return 16 ; -case DRBG_STRENGTH192 : -return 24 ; -case DRBG_STRENGTH256 : -return 32 ; -default : -return 32 ; - } -} -/****************************************************************** * HMAC DRBG functions ******************************************************************/ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,@@ -261,24 +208,24 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,LIST_HEAD (seedlist);LIST_HEAD (vdatalist);if (!reseed) {/* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ -memset (drbg->V,1 ,drbg_statelen (drbg)); +memset (drbg->V,1 ,DRBG_STATE_LEN );drbg_kcapi_hmacsetkey (drbg, drbg->C); } -drbg_string_fill (&seed1, drbg->V,drbg_statelen (drbg)); +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_statelen (drbg)); +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)@@ -319,20 +266,20 @@ static int drbg_hmac_generate(struct drbg_state *drbg, ret =drbg_hmac_update (drbg, addtl,1 );if (ret)return ret; } -drbg_string_fill (&data, drbg->V,drbg_statelen (drbg)); +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; - outlen = (drbg_blocklen (drbg) < (buflen - len)) ? -drbg_blocklen (drbg) : (buflen - len); + outlen = (DRBG_STATE_LEN < (buflen - len)) ? +DRBG_STATE_LEN : (buflen - len);/* 10.1.2.5 step 4.2 */ memcpy (buf + len, drbg->V, outlen); len += outlen; }@@ -375,11 +322,11 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,case DRBG_SEED_STATE_FULL :/* * Seed source has become fully initialized, frequent * reseeds no longer required. */ - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ;break ; }return ret; }@@ -387,25 +334,21 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,static int drbg_seed_from_random (struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) {struct drbg_string data;LIST_HEAD (seedlist); -unsigned int entropylen =drbg_sec_strength (drbg->core->flags); -unsigned char entropy[32 ]; +unsigned char entropy[DRBG_SEC_STRENGTH ];int ret; -BUG_ON (!entropylen); -BUG_ON (entropylen >sizeof (entropy)); - -drbg_string_fill (&data, entropy, entropylen); +drbg_string_fill (&data, entropy,DRBG_SEC_STRENGTH );list_add_tail (&data.list, &seedlist); -get_random_bytes (entropy, entropylen); +get_random_bytes (entropy,DRBG_SEC_STRENGTH ); ret =__drbg_seed (drbg, &seedlist, true,DRBG_SEED_STATE_FULL ); -memzero_explicit (entropy, entropylen); +memzero_explicit (entropy,DRBG_SEC_STRENGTH );return ret; }static bool drbg_nopr_reseed_interval_elapsed (struct drbg_state *drbg) {@@ -442,17 +385,17 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, bool reseed) __must_hold(&drbg->drbg_mutex) {int ret;unsigned char entropy[((32 +16 ) *2 )]; -unsigned int entropylen =drbg_sec_strength (drbg->core->flags); +unsigned int entropylen;struct drbg_string data1;LIST_HEAD (seedlist);enum drbg_seed_state new_seed_state =DRBG_SEED_STATE_FULL ;/* 9.1 / 9.2 / 9.3.1 step 3 */ -if (pers && pers->len > (drbg_max_addtl (drbg))) { +if (pers && pers->len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: personalization string too long %zu\n" , pers->len);return -EINVAL ; }@@ -467,13 +410,14 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,* 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. */ -BUG_ON (!entropylen);if (!reseed) - entropylen = ((entropylen +1 ) /2 ) *3 ; + entropylen = ((DRBG_SEC_STRENGTH +1 ) /2 ) *3 ; +else + entropylen =DRBG_SEC_STRENGTH ;BUG_ON ((entropylen *2 ) >sizeof (entropy));/* Get seed from in-kernel /dev/urandom */ if (!rng_is_initialized ()) new_seed_state =DRBG_SEED_STATE_PARTIAL ;@@ -529,18 +473,18 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,list_add_tail (&pers->list, &seedlist);pr_devel ("DRBG: using personalization string\n" ); }if (!reseed) { -memset (drbg->V,0 ,drbg_statelen (drbg)); -memset (drbg->C,0 ,drbg_statelen (drbg)); +memset (drbg->V,0 ,DRBG_STATE_LEN ); +memset (drbg->C,0 ,DRBG_STATE_LEN ); } ret =__drbg_seed (drbg, &seedlist, reseed, new_seed_state); out: -memzero_explicit (entropy, entropylen *2 ); +memzero_explicit (entropy,sizeof (entropy));return ret; }/* Free all substructures in a DRBG state without the DRBG state structure */ @@ -568,17 +512,17 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) ret =drbg_init_hash_kernel (drbg);if (ret <0 ) goto err; - drbg->Vbuf =kmalloc (drbg_statelen (drbg) + ret,GFP_KERNEL ); + drbg->Vbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL );if (!drbg->Vbuf) { ret = -ENOMEM ; goto fini; } drbg->V =PTR_ALIGN (drbg->Vbuf, ret +1 ); - drbg->Cbuf =kmalloc (drbg_statelen (drbg) + ret,GFP_KERNEL ); + drbg->Cbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL );if (!drbg->Cbuf) { ret = -ENOMEM ; goto fini; } drbg->C =PTR_ALIGN (drbg->Cbuf, ret +1 );@@ -628,24 +572,23 @@ static int drbg_generate(struct drbg_state *drbg,pr_devel ("DRBG: wrong format of additional information\n" );return -EINVAL ; }/* 9.3.1 step 2 */ - len = -EINVAL ; -if (buflen > (drbg_max_request_bytes (drbg))) { +if (buflen >DRBG_MAX_REQUEST_BYTES ) {pr_devel ("DRBG: requested random numbers too large %u\n" , buflen); - goto err; +return -EINVAL ; }/* 9.3.1 step 3 is implicit with the chosen DRBG */ /* 9.3.1 step 4 */ -if (addtl && addtl->len > (drbg_max_addtl (drbg))) { +if (addtl && addtl->len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: additional information string too long %zu\n" , addtl->len); - goto err; +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 @@ -721,12 +664,12 @@ static int drbg_generate_long(struct drbg_state *drbg,unsigned int len =0 ;unsigned int slice =0 ; do { int err = 0; unsigned int chunk = 0; - slice = ((buflen - len) / drbg_max_request_bytes(drbg)); - chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len); + slice = (buflen - len) / DRBG_MAX_REQUEST_BYTES; + chunk = slice ? DRBG_MAX_REQUEST_BYTES : (buflen - len); mutex_lock(&drbg->drbg_mutex); err = drbg_generate(drbg, buf + len, chunk, addtl); mutex_unlock(&drbg->drbg_mutex); if (0 > err) return err;@@ -783,22 +726,21 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,/* 9.1 step 1 is implicit with the selected DRBG type */ /* * 9.1 step 2 is implicit as caller can select prediction resistance -* and the flag is copied into drbg->flags -- * all DRBG types support prediction resistance */ -/* 9.1 step 4 is implicit in drbg_sec_strength */ +/* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ if (!drbg->core) { drbg->core = &drbg_cores[coreref]; drbg->pr = pr; drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; drbg->last_seed_time =0 ; - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ; ret =drbg_alloc_state (drbg);if (ret) goto unlock;@@ -882,11 +824,11 @@ static int drbg_init_hash_kernel(struct drbg_state *drbg)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_blocklen (drbg) !=crypto_shash_digestsize (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 ;@@ -912,11 +854,11 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg)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_statelen (drbg)); +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) {@@ -1058,11 +1000,10 @@ static inline int __init drbg_healthcheck_sanity(void)int ret;int rc = -EFAULT ;bool pr = false;int coreref =0 ;struct drbg_string addtl; -size_t max_addtllen, max_request_bytes;/* only perform test in FIPS mode */ if (!fips_enabled)return 0 ;@@ -1072,28 +1013,26 @@ static inline int __init drbg_healthcheck_sanity(void)if (!drbg)return -ENOMEM ;guard (mutex_init)(&drbg->drbg_mutex); drbg->core = &drbg_cores[coreref]; - drbg->reseed_threshold =drbg_max_requests (drbg); + drbg->reseed_threshold =DRBG_MAX_REQUESTS ;/* * 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. */ - max_addtllen =drbg_max_addtl (drbg); - max_request_bytes =drbg_max_request_bytes (drbg); -drbg_string_fill (&addtl, buf, max_addtllen +1 ); +drbg_string_fill (&addtl, buf,DRBG_MAX_ADDTL +1 );/* overflow addtllen with additional info string */ ret =drbg_generate (drbg, buf,OUTBUFLEN , &addtl);BUG_ON (ret ==0 );/* overflow max_bits */ - ret =drbg_generate (drbg, buf, max_request_bytes +1 ,NULL ); + ret =drbg_generate (drbg, buf,DRBG_MAX_REQUEST_BYTES +1 ,NULL );BUG_ON (ret ==0 );/* overflow max addtllen with personalization string */ ret =drbg_seed (drbg, &addtl, false);BUG_ON (0 == ret);
PATCH 21/38 crypto: drbg - Embed V and C into struct drbg_state
In reply to Eric BiggersNow that the sizes of V and C are known at compile time, embed them into struct drbg_state rather than using separate allocations.
--- crypto/drbg.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-)
crypto/drbg.c +4 -26
@@ -140,14 +140,12 @@ enum drbg_seed_state {*/ #define DRBG_MAX_ADDTL (U32_MAX - 1)struct drbg_state {struct mutex drbg_mutex;/* lock around DRBG */ -unsigned char *V;/* internal state -- 10.1.2.1 1a */ -unsigned char *Vbuf; -unsigned char *C;/* current key -- 10.1.2.1 1b */ -unsigned char *Cbuf; +u8 V[DRBG_STATE_LEN ];/* internal state -- 10.1.2.1 1a */ +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 */
@@ -490,16 +488,12 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,/* Free all substructures in a DRBG state without the DRBG state structure */ static inline void drbg_dealloc_state (struct drbg_state *drbg) {if (!drbg)return ; -kfree_sensitive (drbg->Vbuf); - drbg->Vbuf =NULL ; - drbg->V =NULL ; -kfree_sensitive (drbg->Cbuf); - drbg->Cbuf =NULL ; - drbg->C =NULL ; +memzero_explicit (drbg->V,sizeof (drbg->V)); +memzero_explicit (drbg->C,sizeof (drbg->C)); drbg->reseed_ctr =0 ; drbg->core =NULL ; }/*
@@ -511,28 +505,12 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)int ret = -ENOMEM ; ret =drbg_init_hash_kernel (drbg);if (ret <0 ) goto err; - - drbg->Vbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL ); -if (!drbg->Vbuf) { - ret = -ENOMEM ; - goto fini; - } - drbg->V =PTR_ALIGN (drbg->Vbuf, ret +1 ); - drbg->Cbuf =kmalloc (DRBG_STATE_LEN + ret,GFP_KERNEL ); -if (!drbg->Cbuf) { - ret = -ENOMEM ; - goto fini; - } - drbg->C =PTR_ALIGN (drbg->Cbuf, ret +1 ); -return 0 ; -fini: -drbg_fini_hash_kernel (drbg); err:drbg_dealloc_state (drbg);return ret; }
Signature · 1 line
2.53.0
PATCH 22/38 crypto: drbg - Use HMAC-SHA512 library API
In reply to Eric BiggersSince 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.
--- crypto/Kconfig | 3 +- crypto/drbg.c | 213 ++++++++++--------------------------------------- 2 files changed, 41 insertions(+), 175 deletions(-)
crypto/Kconfig +1 -2
@@ -1113,14 +1113,13 @@ endmenu 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) Enable this only if you need it for a FIPS 140 certification. It's otherwise redundant with the kernel's regular RNG.
crypto/drbg.c +40 -173
415 lines not on this page · raw message
Signature · 1 line
2.53.0
PATCH 23/38 crypto: drbg - Remove drbg_core
In reply to Eric BiggersNow that none of the information in struct drbg_core is used, remove it.
The null-ity of the pointer drbg_state::core was used to keep track of whether the DRBG has been instantiated. Replace it with a boolean.
No functional change.
--- crypto/drbg.c | 99 +++++++-------------------------------------------- 1 file changed, 13 insertions(+), 86 deletions(-)
crypto/drbg.c +13 -86
@@ -98,18 +98,10 @@#include <linux/module.h> #include <linux/mutex.h> #include <linux/string_choices.h> #include <linux/unaligned.h> -struct drbg_state ; - -struct drbg_core { -char cra_name[CRYPTO_MAX_ALG_NAME ];/* mapping to kernel crypto API */ -/* kernel crypto API backend cipher name */ -char backend_cra_name[CRYPTO_MAX_ALG_NAME ]; -}; -enum drbg_seed_state {DRBG_SEED_STATE_UNSEEDED ,DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ DRBG_SEED_STATE_FULL , };
@@ -148,39 +140,21 @@ struct drbg_state {/* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr;size_t reseed_threshold;enum drbg_seed_state seeded;/* DRBG fully seeded? */ unsigned long last_seed_time; +bool instantiated;bool pr;/* Prediction resistance enabled? */ struct crypto_rng *jent; -const struct drbg_core *core;struct drbg_string test_data; };enum drbg_prefixes {DRBG_PREFIX0 =0x00 ,DRBG_PREFIX1 , }; -/*************************************************************** -* Backend cipher definitions available to DRBG -***************************************************************/ - -/* -* The order of the DRBG definitions here matter: every DRBG is registered -* as stdrng. Each DRBG receives an increasing cra_priority values the later -* they are defined in this array (see drbg_fill_array). -* -* Thus, the favored DRBGs are the latest entries in this array. -*/ -static const struct drbg_core drbg_cores[] = { - { - .cra_name ="hmac_sha512" , - .backend_cra_name ="hmac(sha512)" , - }, -}; -static int drbg_uninstantiate (struct drbg_state *drbg);/****************************************************************** * HMAC DRBG functions ******************************************************************/
@@ -453,11 +427,11 @@ static inline void drbg_dealloc_state(struct drbg_state *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 ; - drbg->core =NULL ; + drbg->instantiated = false; }/* * DRBG generate function as required by SP800-90A - this function * generates random numbers
@@ -480,12 +454,12 @@ static int drbg_generate(struct drbg_state *drbg, __must_hold(&drbg->drbg_mutex) {int len =0 ;LIST_HEAD (addtllist); -if (!drbg->core) { -pr_devel ("DRBG: not yet seeded\n" ); +if (!drbg->instantiated) { +pr_devel ("DRBG: not yet instantiated\n" );return -EINVAL ; }if (0 == buflen || !buf) {pr_devel ("DRBG: no output buffer provided\n" );return -EINVAL ;
@@ -623,25 +597,24 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)* @drbg memory of state -- if NULL, new memory is allocated * @pers Personalization string that is mixed into state, may be NULL -- note * the entropy is pulled by the DRBG internally unconditionally * as defined in SP800-90A. The additional input is mixed into * the state in addition to the pulled entropy. -* @coreref reference to core * @pr prediction resistance enabled * * return * 0 on success * error value otherwise */ static int drbg_instantiate (struct drbg_state *drbg,struct drbg_string *pers, -int coreref,bool pr) +bool pr) {int ret;bool reseed = true; -pr_devel ("DRBG: Initializing DRBG core %d with prediction resistance " -"%s\n" , coreref,str_enabled_disabled (pr)); +pr_devel ("DRBG: Initializing DRBG with prediction resistance %s\n" , +str_enabled_disabled (pr));mutex_lock (&drbg->drbg_mutex);/* 9.1 step 1 is implicit with the selected DRBG type */ /*
@@ -649,12 +622,12 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,* all DRBG types support prediction resistance */ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ -if (!drbg->core) { - drbg->core = &drbg_cores[coreref]; +if (!drbg->instantiated) { + drbg->instantiated = true; drbg->pr = pr; drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; drbg->last_seed_time =0 ; drbg->reseed_threshold =DRBG_MAX_REQUESTS ;
@@ -718,50 +691,10 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm,/*************************************************************** * Kernel crypto API interface to register DRBG ***************************************************************/ -/* -* Look up the DRBG flags by given kernel crypto API cra_name -* The code uses the drbg_cores definition to do this -* -* @cra_name kernel crypto API cra_name -* @coreref reference to integer which is filled with the pointer to -* the applicable core -* @pr reference for setting prediction resistance -* -* return: flags -*/ -static inline void drbg_convert_tfm_core (const char *cra_driver_name, -int *coreref,bool *pr) -{ -int i =0 ; -size_t start =0 ; -int len =0 ; - - *pr = true; -/* disassemble the names */ -if (!memcmp (cra_driver_name,"drbg_nopr_" ,10 )) { - start =10 ; - *pr = false; - }else if (!memcmp (cra_driver_name,"drbg_pr_" ,8 )) { - start =8 ; - }else { -return ; - } - -/* remove the first part */ - len =strlen (cra_driver_name) - start; -for (i =0 ;ARRAY_SIZE (drbg_cores) > i; i++) { -if (!memcmp (cra_driver_name + start, drbg_cores[i].cra_name, - len)) { - *coreref = i; -return ; - } - } -} -static int drbg_kcapi_init (struct crypto_tfm *tfm) {struct drbg_state *drbg =crypto_tfm_ctx (tfm);mutex_init (&drbg->drbg_mutex);
@@ -806,23 +739,21 @@ static int drbg_kcapi_random(struct crypto_rng *tfm,static int drbg_kcapi_seed (struct crypto_rng *tfm,const u8 *seed,unsigned int slen) {struct drbg_state *drbg =crypto_rng_ctx (tfm);struct crypto_tfm *tfm_base =crypto_rng_tfm (tfm); -bool pr = false; +bool pr =memcmp (crypto_tfm_alg_driver_name (tfm_base), +"drbg_nopr_" ,10 ) !=0 ;struct drbg_string string;struct drbg_string *seed_string =NULL ; -int coreref =0 ; -drbg_convert_tfm_core (crypto_tfm_alg_driver_name (tfm_base), &coreref, - &pr);if (0 < slen) {drbg_string_fill (&string, seed, slen); seed_string = &string; } -return drbg_instantiate (drbg, seed_string, coreref, pr); +return drbg_instantiate (drbg, seed_string, pr); }/*************************************************************** * Kernel module: code to load the module ***************************************************************/
@@ -842,26 +773,22 @@ static inline int __init drbg_healthcheck_sanity(void)#define OUTBUFLEN 16unsigned char buf[OUTBUFLEN ];struct drbg_state *drbg =NULL ;int ret;int rc = -EFAULT ; -bool pr = false; -int coreref =0 ;struct drbg_string addtl;/* only perform test in FIPS mode */ if (!fips_enabled)return 0 ; -drbg_convert_tfm_core ("drbg_nopr_hmac_sha512" , &coreref, &pr); - drbg = kzalloc_obj(struct drbg_state);if (!drbg)return -ENOMEM ;guard (mutex_init)(&drbg->drbg_mutex); - drbg->core = &drbg_cores[coreref]; + drbg->instantiated = true; drbg->reseed_threshold =DRBG_MAX_REQUESTS ;/* * if the following tests fail, it is likely that there is a buffer * overflow as buf is much smaller than the requested or provided
Signature · 1 line
2.53.0
PATCH 24/38 crypto: drbg - Install separate seed functions for pr and nopr
In reply to Eric BiggersSet rng_alg::seed to different functions for the prediction-resistant and non-prediction-resistant algorithms, so that the function does not need to parse the algorithm name to figure out which algorithm it is.
--- crypto/drbg.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
crypto/drbg.c +16 -9
@@ -731,20 +731,15 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, }return drbg_generate_long (drbg, dst, dlen, addtl); } -/* -* Seed the DRBG invoked by the kernel crypto API -*/ +/* Seed (i.e. instantiate) or re-seed the DRBG. */ static int drbg_kcapi_seed (struct crypto_rng *tfm, -const u8 *seed,unsigned int slen) +const u8 *seed,unsigned int slen,bool pr) {struct drbg_state *drbg =crypto_rng_ctx (tfm); -struct crypto_tfm *tfm_base =crypto_rng_tfm (tfm); -bool pr =memcmp (crypto_tfm_alg_driver_name (tfm_base), -"drbg_nopr_" ,10 ) !=0 ;struct drbg_string string;struct drbg_string *seed_string =NULL ;if (0 < slen) {drbg_string_fill (&string, seed, slen);
@@ -752,10 +747,22 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, }return drbg_instantiate (drbg, seed_string, pr); } +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); +} +/*************************************************************** * Kernel module: code to load the module ***************************************************************/ /*
@@ -825,11 +832,11 @@ static struct rng_alg drbg_algs[] = { .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, + .seed = drbg_kcapi_seed_pr, .generate = drbg_kcapi_random, .base.cra_exit = drbg_kcapi_cleanup, }, { .base.cra_name = "stdrng",
@@ -837,11 +844,11 @@ static struct rng_alg drbg_algs[] = { .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, + .seed = drbg_kcapi_seed_nopr, .generate = drbg_kcapi_random, .base.cra_exit = drbg_kcapi_cleanup, }, };
Signature · 1 line
2.53.0
PATCH 25/38 crypto: drbg - Move module aliases to end of file
In reply to Eric BiggersMove the MODULE_ALIAS_CRYPTO lines in the middle of the file to the end so that they are in the usual place and next to the other one.
--- crypto/drbg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
crypto/drbg.c +2 -3
@@ -157,13 +157,10 @@ static int drbg_uninstantiate(struct drbg_state *drbg);/****************************************************************** * HMAC DRBG functions ******************************************************************/ -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 void drbg_hmac_update (struct drbg_state *drbg,struct list_head *seed,int reseed) {int i =0 ;
@@ -881,5 +878,7 @@ 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" );
Signature · 1 line
2.53.0
PATCH 26/38 crypto: drbg - Consolidate "instantiate" logic and remove drbg_state::C
In reply to Eric BiggersCurrently some of the steps of "Instantiate the DRBG" occur in a convoluted way in different places in the call stack:
drbg_instantiate()
=> drbg_seed(reseed=0) sets the raw HMAC key drbg_state::C to its
correct initial value, and it sets the state value drbg_state::V to an *incorrect* initial value.
=> drbg_hmac_update(reseed=0) overwrites drbg_state::V with the
correct initial value, then prepares the hmac_sha512_key drbg_state::key from the initial raw HMAC key drbg_state::C.
Later, each time the HMAC key is updated, drbg_hmac_update() also uses drbg_state::C to temporarily store the new raw key.
Simplify all of this by:
- Making drbg_instantiate() set the correct initial values of drbg_state::V and drbg_state::key.
- Converting drbg_hmac_update() to generate the raw key in a temporary on-stack array instead of drbg_state::C.
- Removing drbg_state::C.
--- crypto/drbg.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-)
crypto/drbg.c +15 -23
@@ -134,11 +134,10 @@ 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;enum drbg_seed_state seeded;/* DRBG fully seeded? */ unsigned long last_seed_time;
@@ -158,21 +157,15 @@ static int drbg_uninstantiate(struct drbg_state *drbg);/****************************************************************** * HMAC DRBG functions ******************************************************************/ /* update function of HMAC DRBG as defined in 10.1.2.2 */ -static void 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 i =0 ;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 ); -hmac_sha512_preparekey (&drbg->key, drbg->C,DRBG_STATE_LEN ); - } +u8 new_key[DRBG_STATE_LEN ];for (i =2 ;0 < i; i--) {/* first round uses 0x0, second 0x1 */ unsigned char prefix =DRBG_PREFIX0 ;if (1 == i)
@@ -186,20 +179,21 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,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 ); +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 (!seed)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, unsigned char *buf,
@@ -208,11 +202,11 @@ static void drbg_hmac_generate(struct drbg_state *drbg, {int len =0 ;/* 10.1.2.5 step 2 */ if (addtl && !list_empty (addtl)) -drbg_hmac_update (drbg, addtl,1 ); +drbg_hmac_update (drbg, addtl);while (len < buflen) {unsigned int outlen =0 ;/* 10.1.2.5 step 4.1 */
@@ -225,19 +219,19 @@ static void drbg_hmac_generate(struct drbg_state *drbg, len += outlen; }/* 10.1.2.5 step 6 */ if (addtl && !list_empty (addtl)) -drbg_hmac_update (drbg, addtl,1 ); +drbg_hmac_update (drbg, addtl);else -drbg_hmac_update (drbg,NULL ,1 ); +drbg_hmac_update (drbg,NULL ); }static inline void __drbg_seed (struct drbg_state *drbg,struct list_head *seed, -int reseed,enum drbg_seed_state new_seed_state) +enum drbg_seed_state new_seed_state) { -drbg_hmac_update (drbg, seed, reseed); +drbg_hmac_update (drbg, seed); drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; drbg->reseed_ctr =1 ;
@@ -273,11 +267,11 @@ static void drbg_seed_from_random(struct drbg_state *drbg)drbg_string_fill (&data, entropy,DRBG_SEC_STRENGTH );list_add_tail (&data.list, &seedlist);get_random_bytes (entropy,DRBG_SEC_STRENGTH ); -__drbg_seed (drbg, &seedlist, true,DRBG_SEED_STATE_FULL ); +__drbg_seed (drbg, &seedlist,DRBG_SEED_STATE_FULL );memzero_explicit (entropy,DRBG_SEC_STRENGTH ); }static bool drbg_nopr_reseed_interval_elapsed (struct drbg_state *drbg)
@@ -402,16 +396,12 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,if (pers && pers->buf &&0 < pers->len) {list_add_tail (&pers->list, &seedlist);pr_devel ("DRBG: using personalization string\n" ); } -if (!reseed) { -memset (drbg->V,0 ,DRBG_STATE_LEN ); -memset (drbg->C,0 ,DRBG_STATE_LEN ); - } -__drbg_seed (drbg, &seedlist, reseed, new_seed_state); +__drbg_seed (drbg, &seedlist, new_seed_state); ret =0 ; out:memzero_explicit (entropy,sizeof (entropy));return ret;
@@ -422,11 +412,10 @@ 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 ; drbg->instantiated = false; }/*
@@ -603,10 +592,11 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)* error value otherwise */ static int drbg_instantiate (struct drbg_state *drbg,struct drbg_string *pers,bool pr) { +static const u8 initial_key[DRBG_STATE_LEN ];/* all zeroes */ int ret;bool reseed = true;pr_devel ("DRBG: Initializing DRBG with prediction resistance %s\n" ,str_enabled_disabled (pr));
@@ -625,10 +615,12 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, drbg->instantiated = true; drbg->pr = pr; drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; drbg->last_seed_time =0 ; drbg->reseed_threshold =DRBG_MAX_REQUESTS ; +memset (drbg->V,1 ,DRBG_STATE_LEN ); +hmac_sha512_preparekey (&drbg->key, initial_key,DRBG_STATE_LEN ); ret =drbg_prepare_hrng (drbg);if (ret) goto free_everything;
Signature · 1 line
2.53.0
PATCH 27/38 crypto: drbg - Eliminate use of 'drbg_string' and lists
In reply to Eric BiggersUse straightforward (buffer, len) parameters instead of struct drbg_string or lists of strings. This simplifies the code considerably.
For now struct drbg_string is still used in crypto_drbg_ctr_df(), so move its definition to crypto/df_sp80090a.h.
--- crypto/df_sp80090a.c | 1 - crypto/drbg.c | 179 +++++++++++----------------- drivers/crypto/xilinx/xilinx-trng.c | 1 - include/crypto/df_sp80090a.h | 25 ++++ include/crypto/internal/drbg.h | 39 ------ 5 files changed, 94 insertions(+), 151 deletions(-) delete mode 100644 include/crypto/internal/drbg.h
crypto/df_sp80090a.c +0 -1
@@ -11,11 +11,10 @@#include <linux/module.h> #include <linux/string.h> #include <linux/unaligned.h> #include <crypto/aes.h> #include <crypto/df_sp80090a.h> -#include <crypto/internal/drbg.h> static void drbg_kcapi_sym (struct aes_enckey *aeskey,unsigned char *outval,const struct drbg_string *in,u8 blocklen_bytes) {/* there is only component in *in */
crypto/drbg.c +69 -110
523 lines not on this page · raw message
drivers/crypto/xilinx/xilinx-trng.c +0 -1
@@ -17,11 +17,10 @@#include <linux/mutex.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <crypto/aes.h> #include <crypto/df_sp80090a.h> -#include <crypto/internal/drbg.h> #include <crypto/internal/cipher.h> #include <crypto/internal/rng.h> /* TRNG Registers Offsets */ #define TRNG_STATUS_OFFSET 0x4U
include/crypto/df_sp80090a.h +25 -0
@@ -7,10 +7,35 @@#ifndef _CRYPTO_DF80090A_H#define _CRYPTO_DF80090A_H#include <crypto/internal/cipher.h> #include <crypto/aes.h> +#include <linux/list.h> + +/* +* Concatenation Helper and string operation helper +* +* SP800-90A requires the concatenation of different data. To avoid copying +* buffers around or allocate additional memory, the following data structure +* is used to point to the original memory with its size. In addition, it +* is used to build a linked list. The linked list defines the concatenation +* of individual buffers. The order of memory block referenced in that +* linked list determines the order of concatenation. +*/ +struct drbg_string { +const unsigned char *buf; +size_t len; +struct list_head list; +}; + +static inline void drbg_string_fill (struct drbg_string *string, +const unsigned char *buf,size_t len) +{ + string->buf = buf; + string->len = len; +INIT_LIST_HEAD (&string->list); +}static inline int crypto_drbg_ctr_df_datalen (u8 statelen,u8 blocklen) {return statelen +/* df_data */ blocklen + /* pad */
include/crypto/internal/drbg.h deleted +0 -39
@@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* -* NIST SP800-90A DRBG derivation function -* -* Copyright (C) 2014, Stephan Mueller <[email protected]> -*/ - -#ifndef _INTERNAL_DRBG_H -#define _INTERNAL_DRBG_H - -#include <linux/list.h> -#include <linux/types.h> - -/* -* Concatenation Helper and string operation helper -* -* SP800-90A requires the concatenation of different data. To avoid copying -* buffers around or allocate additional memory, the following data structure -* is used to point to the original memory with its size. In addition, it -* is used to build a linked list. The linked list defines the concatenation -* of individual buffers. The order of memory block referenced in that -* linked list determines the order of concatenation. -*/ -struct drbg_string { -const unsigned char *buf; -size_t len; -struct list_head list; -}; - -static inline void drbg_string_fill (struct drbg_string *string, -const unsigned char *buf,size_t len) -{ - string->buf = buf; - string->len = len; -INIT_LIST_HEAD (&string->list); -} - -#endif //_INTERNAL_DRBG_H
Signature · 1 line
2.53.0
PATCH 28/38 crypto: drbg - Simplify drbg_generate_long() and fold into caller
In reply to Eric BiggersSimplify drbg_generate_long() to use a more straightforward loop, and then fold it into its only caller. No functional change.
--- crypto/drbg.c | 48 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 31 deletions(-)
crypto/drbg.c +17 -31
@@ -504,39 +504,10 @@ static int drbg_generate(struct drbg_state *drbg, len =0 ; err:return len; } -/* -* Wrapper around drbg_generate which can pull arbitrary long strings -* from the DRBG without hitting the maximum request limitation. -* -* Parameters: see drbg_generate -* Return codes: see drbg_generate -- if one drbg_generate request fails, -* the entire drbg_generate_long request fails -*/ -static int drbg_generate_long (struct drbg_state *drbg, -unsigned char *buf,unsigned int buflen, -const u8 *addtl,size_t addtl_len) -{ -unsigned int len =0 ; -unsigned int slice =0 ; -do { -int err =0 ; -unsigned int chunk =0 ; - slice = (buflen - len) /DRBG_MAX_REQUEST_BYTES ; - chunk = slice ?DRBG_MAX_REQUEST_BYTES : (buflen - len); -mutex_lock (&drbg->drbg_mutex); - err =drbg_generate (drbg, buf + len, chunk, addtl, addtl_len); -mutex_unlock (&drbg->drbg_mutex); -if (0 > err) -return err; - len += chunk; - }while (slice >0 && (len < buflen)); -return 0 ; -} -static int drbg_prepare_hrng (struct drbg_state *drbg) {/* We do not need an HRNG in test mode. */ if (drbg->test_entropylen !=0 )return 0 ;
@@ -674,11 +645,10 @@ static void drbg_kcapi_cleanup(struct crypto_tfm *tfm)drbg_uninstantiate (crypto_tfm_ctx (tfm)); }/* * Generate random numbers invoked by the kernel crypto API: -* The API of the kernel crypto API is extended as follows: * * 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.
@@ -687,11 +657,27 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { struct drbg_state *drbg = crypto_rng_ctx(tfm); -return drbg_generate_long (drbg, dst, dlen, src, slen); +/* +* 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 ; }/* Seed (i.e. instantiate) or re-seed the DRBG. */ static int drbg_kcapi_seed (struct crypto_rng *tfm,const u8 *seed,unsigned int slen,bool pr)
Signature · 1 line
2.53.0
PATCH 29/38 crypto: drbg - Put rng_alg methods in logical order
In reply to Eric BiggersPut the DRBG implementation of the rng_alg methods in the order in which they're called (cra_init => set_ent => seed => generate => cra_exit) so that it's easier to understand the flow.
Also rename drbg_kcapi_random to drbg_kcapi_generate, and drbg_kcapi_cleanup to drbg_kcapi_exit, so they match the method names.
--- crypto/drbg.c | 82 ++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 46 deletions(-)
crypto/drbg.c +36 -46
@@ -607,17 +607,24 @@ static int drbg_uninstantiate(struct drbg_state *drbg)drbg_dealloc_state (drbg);/* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0 ; } -/* -* Helper function for setting the test data in the DRBG -* -* @drbg DRBG state handle -* @data test data -* @len test data length -*/ +/*************************************************************** +* 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);
@@ -625,39 +632,42 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, drbg->test_entropy = data; drbg->test_entropylen = len;mutex_unlock (&drbg->drbg_mutex); } -/*************************************************************** -* Kernel crypto API interface to register DRBG -***************************************************************/ - -static int drbg_kcapi_init (struct crypto_tfm *tfm) +/* Seed (i.e. instantiate) or re-seed the DRBG. */ +static int drbg_kcapi_seed (struct crypto_rng *tfm, +const u8 *seed,unsigned int slen,bool pr) { -struct drbg_state *drbg =crypto_tfm_ctx (tfm); +struct drbg_state *drbg =crypto_rng_ctx (tfm); -mutex_init (&drbg->drbg_mutex); +return drbg_instantiate (drbg, seed, slen, pr); +} -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 void drbg_kcapi_cleanup (struct crypto_tfm *tfm) +static int drbg_kcapi_seed_nopr (struct crypto_rng *tfm, +const u8 *seed,unsigned int slen) { -drbg_uninstantiate (crypto_tfm_ctx (tfm)); +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. * dst is the output buffer where random data is to be stored. * dlen is the length of dst. */ -static int drbg_kcapi_random (struct crypto_rng *tfm, -const u8 *src,unsigned int slen, -u8 *dst,unsigned int dlen) +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
@@ -676,35 +686,15 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, dlen -= n; }while (dlen);return 0 ; } -/* Seed (i.e. instantiate) or re-seed the DRBG. */ -static int drbg_kcapi_seed (struct crypto_rng *tfm, -const u8 *seed,unsigned int slen,bool pr) +static void drbg_kcapi_exit (struct crypto_tfm *tfm) { -struct drbg_state *drbg =crypto_rng_ctx (tfm); - -return drbg_instantiate (drbg, seed, slen, pr); -} - -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); +drbg_uninstantiate (crypto_tfm_ctx (tfm)); } -/*************************************************************** -* Kernel module: code to load the module -***************************************************************/ -/* * 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
@@ -767,24 +757,24 @@ static struct rng_alg drbg_algs[] = { .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_random, - .base.cra_exit = drbg_kcapi_cleanup, + .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_random, - .base.cra_exit = drbg_kcapi_cleanup, + .generate = drbg_kcapi_generate, + .base.cra_exit = drbg_kcapi_exit, }, };static int __init drbg_init (void ) {
Signature · 1 line
2.53.0
PATCH 30/38 crypto: drbg - Fold drbg_instantiate() into drbg_kcapi_seed()
In reply to Eric BiggersFold drbg_instantiate() into its only caller.
--- crypto/drbg.c | 107 ++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 64 deletions(-)
crypto/drbg.c +43 -64
@@ -524,27 +524,60 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)return 0 ; }/* -* DRBG instantiation function as required by SP800-90A - this function -* sets up the DRBG handle, performs the initial seeding and all sanity -* checks required by SP800-90A +* DRBG uninstantiate function as required by SP800-90A - this function +* frees all buffers and the DRBG handle * -* @drbg memory of state -- if NULL, new memory is allocated -* @pers Optional personalization string that is mixed into state -* @pers_len Length of personalization string in bytes, may be 0 -* @pr prediction resistance enabled +* @drbg DRBG state handle * * return * 0 on success -* error value otherwise */ -static int drbg_instantiate (struct drbg_state *drbg, -const u8 *pers,size_t pers_len,bool pr) +static int drbg_uninstantiate (struct drbg_state *drbg) +{ +if (!IS_ERR_OR_NULL (drbg->jent)) +crypto_free_rng (drbg->jent); + drbg->jent =NULL ; + +drbg_dealloc_state (drbg); +/* no scrubbing of test_data -- this shall survive an uninstantiate */ +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,size_t pers_len,bool pr) {static const u8 initial_key[DRBG_STATE_LEN ];/* all zeroes */ +struct drbg_state *drbg =crypto_rng_ctx (tfm);int ret;bool reseed = true;pr_devel ("DRBG: Initializing DRBG with prediction resistance %s\n" ,str_enabled_disabled (pr));
@@ -587,64 +620,10 @@ static int drbg_instantiate(struct drbg_state *drbg,mutex_unlock (&drbg->drbg_mutex);drbg_uninstantiate (drbg);return ret; } -/* -* DRBG uninstantiate function as required by SP800-90A - this function -* frees all buffers and the DRBG handle -* -* @drbg DRBG state handle -* -* return -* 0 on success -*/ -static int drbg_uninstantiate (struct drbg_state *drbg) -{ -if (!IS_ERR_OR_NULL (drbg->jent)) -crypto_free_rng (drbg->jent); - drbg->jent =NULL ; - -drbg_dealloc_state (drbg); -/* no scrubbing of test_data -- this shall survive an uninstantiate */ -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 *seed,unsigned int slen,bool pr) -{ -struct drbg_state *drbg =crypto_rng_ctx (tfm); - -return drbg_instantiate (drbg, seed, slen, pr); -} -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); }
Signature · 1 line
2.53.0
PATCH 31/38 crypto: drbg - Separate "reseed" case in drbg_kcapi_seed()
In reply to Eric BiggersClearly separate the code for the "reseed" and "instantiate" cases, since what they need to do is quite different.
Note that the mutex guard makes the mutex start being held during the call to drbg_uninstantiate(), which is fine.
--- crypto/drbg.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-)
crypto/drbg.c +16 -22
@@ -575,51 +575,45 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, const u8 *pers, size_t pers_len, bool pr) { static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */struct drbg_state *drbg =crypto_rng_ctx (tfm);int ret; -bool reseed = true;pr_devel ("DRBG: Initializing DRBG with prediction resistance %s\n" ,str_enabled_disabled (pr)); -mutex_lock (&drbg->drbg_mutex); +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 4 is implicit in DRBG_SEC_STRENGTH */ -if (!drbg->instantiated) { - drbg->instantiated = true; - drbg->pr = pr; - drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; - drbg->last_seed_time =0 ; - drbg->reseed_threshold =DRBG_MAX_REQUESTS ; -memset (drbg->V,1 ,DRBG_STATE_LEN ); -hmac_sha512_preparekey (&drbg->key, initial_key,DRBG_STATE_LEN ); - - ret =drbg_prepare_hrng (drbg); -if (ret) - goto free_everything; - - reseed = false; - } - - ret =drbg_seed (drbg, pers, pers_len, reseed); + drbg->instantiated = true; + drbg->pr = pr; + drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; + drbg->last_seed_time =0 ; + drbg->reseed_threshold =DRBG_MAX_REQUESTS ; +memset (drbg->V,1 ,DRBG_STATE_LEN ); +hmac_sha512_preparekey (&drbg->key, initial_key,DRBG_STATE_LEN ); -if (ret && !reseed) + ret =drbg_prepare_hrng (drbg); +if (ret) + goto free_everything; + ret =drbg_seed (drbg, pers, pers_len,/* reseed= */ false); +if (ret) goto free_everything; -mutex_unlock (&drbg->drbg_mutex);return ret; free_everything: -mutex_unlock (&drbg->drbg_mutex);drbg_uninstantiate (drbg);return ret; } static int drbg_kcapi_seed_pr(struct crypto_rng *tfm,
Signature · 1 line
2.53.0
PATCH 32/38 crypto: drbg - Fold drbg_prepare_hrng() into drbg_kcapi_seed()
In reply to Eric BiggersFold drbg_prepare_hrng() into its only caller.
--- crypto/drbg.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-)
crypto/drbg.c +12 -22
@@ -504,29 +504,10 @@ static int drbg_generate(struct drbg_state *drbg, len =0 ; err:return len; } -static int drbg_prepare_hrng (struct drbg_state *drbg) -{ -/* We do not need an HRNG in test mode. */ -if (drbg->test_entropylen !=0 ) -return 0 ; - - drbg->jent =crypto_alloc_rng ("jitterentropy_rng" ,0 ,0 ); -if (IS_ERR (drbg->jent)) { -const int err =PTR_ERR (drbg->jent); - - drbg->jent =NULL ; -if (fips_enabled) -return err; -pr_info ("DRBG: Continuing without Jitter RNG\n" ); - } - -return 0 ; -} -/* * DRBG uninstantiate function as required by SP800-90A - this function * frees all buffers and the DRBG handle * * @drbg DRBG state handle
@@ -600,13 +581,22 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, drbg->last_seed_time =0 ; drbg->reseed_threshold =DRBG_MAX_REQUESTS ;memset (drbg->V,1 ,DRBG_STATE_LEN );hmac_sha512_preparekey (&drbg->key, initial_key,DRBG_STATE_LEN ); - ret =drbg_prepare_hrng (drbg); -if (ret) - goto free_everything; +/* 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) + goto free_everything; +pr_info ("DRBG: Continuing without Jitter RNG\n" ); + } + } + ret =drbg_seed (drbg, pers, pers_len,/* reseed= */ false);if (ret) goto free_everything;return ret;
Signature · 1 line
2.53.0
PATCH 33/38 crypto: drbg - Simplify "uninstantiate" logic
In reply to Eric Biggersdrbg_kcapi_seed() calls drbg_uninstantiate() only to free drbg->jent and set drbg->instantiated = false. However, the latter is necessary only because drbg_kcapi_seed() sets drbg->instantiated = true too early. Fix that, then just inline the freeing of drbg->jent.
Then, simplify the actual "uninstantiate" in drbg_kcapi_exit(). Just free drbg->jent (note that this is a no-op on error and null pointers), then memzero_explicit() the entire drbg_state.
Note that in reality the memzero_explicit() is redundant, since the crypto_rng API zeroizes the memory anyway. But the way SP800-90A is worded, it's easy to imagine that someone assessing conformance with it would be looking for code in drbg.c that says it does an "Uninstantiate" and does the zeroization. So it's probably worth keeping it somewhat explicit, even though that means double zeroization in practice.
--- crypto/drbg.c | 57 ++++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 44 deletions(-)
crypto/drbg.c +13 -44
@@ -150,12 +150,10 @@ struct drbg_state {enum drbg_prefixes {DRBG_PREFIX0 =0x00 ,DRBG_PREFIX1 , }; -static int drbg_uninstantiate (struct drbg_state *drbg); -/****************************************************************** * HMAC DRBG functions ******************************************************************/ /* update function of HMAC DRBG as defined in 10.1.2.2 */
@@ -388,21 +386,10 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len,memzero_explicit (entropy_buf,sizeof (entropy_buf));return ret; } -/* Free all substructures in a DRBG state without the DRBG state structure */ -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)); - drbg->reseed_ctr =0 ; - drbg->instantiated = false; -} -/* * DRBG generate function as required by SP800-90A - this function * generates random numbers * * @drbg DRBG state handle
@@ -504,30 +491,10 @@ static int drbg_generate(struct drbg_state *drbg, len =0 ; err:return len; } -/* -* DRBG uninstantiate function as required by SP800-90A - this function -* frees all buffers and the DRBG handle -* -* @drbg DRBG state handle -* -* return -* 0 on success -*/ -static int drbg_uninstantiate (struct drbg_state *drbg) -{ -if (!IS_ERR_OR_NULL (drbg->jent)) -crypto_free_rng (drbg->jent); - drbg->jent =NULL ; - -drbg_dealloc_state (drbg); -/* no scrubbing of test_data -- this shall survive an uninstantiate */ -return 0 ; -} -/*************************************************************** * Kernel crypto API interface to DRBG ***************************************************************/ static int drbg_kcapi_init (struct crypto_tfm *tfm)
@@ -573,11 +540,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,* all DRBG types support prediction resistance */ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - drbg->instantiated = true; drbg->pr = pr; drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; drbg->last_seed_time =0 ; drbg->reseed_threshold =DRBG_MAX_REQUESTS ;memset (drbg->V,1 ,DRBG_STATE_LEN );
@@ -588,24 +554,23 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, 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) - goto free_everything; +return ret;pr_info ("DRBG: Continuing without Jitter RNG\n" ); } } ret =drbg_seed (drbg, pers, pers_len,/* reseed= */ false); -if (ret) - goto free_everything; - -return ret; - -free_everything: -drbg_uninstantiate (drbg); -return ret; +if (ret) { +crypto_free_rng (drbg->jent); + drbg->jent =NULL ; +return ret; + } + drbg->instantiated = true; +return 0 ; }static int drbg_kcapi_seed_pr (struct crypto_rng *tfm,const u8 *seed,unsigned int slen) {
@@ -649,13 +614,17 @@ static int drbg_kcapi_generate(struct crypto_rng *tfm, dlen -= n; }while (dlen);return 0 ; } +/* Uninstantiate the DRBG. */ static void drbg_kcapi_exit (struct crypto_tfm *tfm) { -drbg_uninstantiate (crypto_tfm_ctx (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.
Signature · 1 line
2.53.0
PATCH 34/38 crypto: drbg - Include get_random_bytes() output in additional input
In reply to Eric BiggersWoodage & Shumow (2018) (https://eprint.iacr.org/2018/349.pdf) showed that contrary to the claims made by NIST in SP800-90A, HMAC_DRBG doesn't satisfy the formal definition of forward secrecy (i.e. "backtracking resistance") when it's called with an empty additional input string.
The actual attack seems pretty benign, as it doesn't actually give the attacker any previous RNG output, but rather just allows them to test whether their guess of the previous block of RNG output is correct. Regardless, it's an annoying design flaw, and it's yet another example of why NIST's DRBGs aren't all that great.
Meanwhile, the kernel's HMAC_DRBG code also tries to reseed itself automatically after random.c has reseeded itself. But the implementation is buggy, as it just checks whether 300 seconds have elapsed, rather than looking at the actual generation counter.
Let's just follow the example of BoringSSL and use the conservative approach of always including 32 bytes of "regular" random data in the additional input string. This fixes both issues described above.
This does reduce performance. But this should be tolerable, since:
- Due to earlier changes, the kernel code that was previously using drbg.c regardless of FIPS mode is now using it only in FIPS mode.
- The additional input string is processed only once per request. So if a lot of bytes are generated at once, the cost is amortized.
- The NIST DRBGs are notoriously slow anyway.
Note that this fix should have no impact (either positive or negative) on FIPS 140 certifiability. From FIPS's point of view the code added by this commit simply doesn't matter: it adds zero entropy to something that doesn't need to contain entropy.
--- crypto/drbg.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
crypto/drbg.c +25 -4
@@ -191,17 +191,36 @@ static void drbg_hmac_update(struct drbg_state *drbg,/* generate function of HMAC DRBG as defined in 10.1.2.5 */ static void drbg_hmac_generate (struct drbg_state *drbg,unsigned char *buf,unsigned int buflen, -const u8 *addtl,size_t addtl_len) +const u8 *addtl1,size_t addtl1_len) {int len =0 ; +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 (addtl_len) -drbg_hmac_update (drbg, addtl, addtl_len,NULL ,0 ); +if (addtl1_len || addtl2_len) +drbg_hmac_update (drbg, addtl1, addtl1_len, addtl2, addtl2_len);while (len < buflen) {unsigned int outlen =0 ;/* 10.1.2.5 step 4.1 */
@@ -213,11 +232,13 @@ static void drbg_hmac_generate(struct drbg_state *drbg,memcpy (buf + len, drbg->V, outlen); len += outlen; }/* 10.1.2.5 step 6 */ -drbg_hmac_update (drbg, addtl, addtl_len,NULL ,0 ); +drbg_hmac_update (drbg, addtl1, addtl1_len, addtl2, addtl2_len); + +memzero_explicit (addtl2,sizeof (addtl2)); } static inline void __drbg_seed(struct drbg_state *drbg, const u8 *seed1, size_t seed1_len, const u8 *seed2, size_t seed2_len,
Signature · 1 line
2.53.0
PATCH 35/38 crypto: drbg - Change DRBG_MAX_REQUESTS to 4096
In reply to Eric BiggersCurrently a formal reseed happens only after each 1048576 requests.
That's quite a high number. Let's follow the example of BoringSSL and use a more conservative value of 4096.
Note that in practice this makes little difference, now that we're including 32 bytes from get_random_bytes() in the additional input on every request anyway, which is a de facto reseed.
But for the same reason, we might as well decrease the actual reseed interval to something more reasonable.
--- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/drbg.c +1 -1
@@ -113,11 +113,11 @@ enum drbg_seed_state {/* * 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 (1 << 20) +#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. */
Signature · 1 line
2.53.0
PATCH 36/38 crypto: drbg - Remove redundant reseeding based on random.c state
In reply to Eric BiggersWe're now incorporating 32 bytes from get_random_bytes() in the additional input string on every request. The additional input string is processed with a call to drbg_hmac_update(), which is exactly how the seed is processed. Thus, in reality this is as good as a reseed.
From the perspective of FIPS 140-3, it isn't as good as a reseed. But it doesn't actually matter, because from FIPS's point of view get_random_bytes() provides zero entropy anyway.
Thus, neither the reseed with more get_random_bytes() every 300s, nor the logic that reseeds more frequently before rng_is_initialized(), is actually needed anymore. Remove it to simplify the code significantly.
(Technically the use of get_random_bytes() in drbg_seed() itself could be removed too. But it's safer to keep it there for now.)
--- crypto/drbg.c | 107 +++++--------------------------------------------- 1 file changed, 9 insertions(+), 98 deletions(-)
crypto/drbg.c +9 -98
@@ -91,22 +91,15 @@#include <crypto/internal/rng.h> #include <crypto/sha2.h> #include <linux/fips.h> #include <linux/kernel.h> -#include <linux/jiffies.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/string_choices.h> #include <linux/unaligned.h> -enum drbg_seed_state { -DRBG_SEED_STATE_UNSEEDED , -DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ -DRBG_SEED_STATE_FULL , -}; -/* State length in bytes */ #define DRBG_STATE_LEN SHA512_DIGEST_SIZE/* Security strength in bytes */ #define DRBG_SEC_STRENGTH (SHA512_DIGEST_SIZE / 2)
@@ -135,13 +128,10 @@ 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; -size_t reseed_threshold; -enum drbg_seed_state seeded;/* DRBG fully seeded? */ -unsigned long last_seed_time;bool instantiated;bool pr;/* Prediction resistance enabled? */ struct crypto_rng *jent;const u8 *test_entropy;size_t test_entropylen;
@@ -237,76 +227,10 @@ static void drbg_hmac_generate(struct drbg_state *drbg,drbg_hmac_update (drbg, addtl1, addtl1_len, addtl2, addtl2_len);memzero_explicit (addtl2,sizeof (addtl2)); } -static inline void __drbg_seed (struct drbg_state *drbg, -const u8 *seed1,size_t seed1_len, -const u8 *seed2,size_t seed2_len, -enum drbg_seed_state new_seed_state) -{ -drbg_hmac_update (drbg, seed1, seed1_len, seed2, seed2_len); - - drbg->seeded = new_seed_state; - drbg->last_seed_time = jiffies; - drbg->reseed_ctr =1 ; - -switch (drbg->seeded) { -case DRBG_SEED_STATE_UNSEEDED : -/* Impossible, but handle it to silence compiler warnings. */ - fallthrough; -case DRBG_SEED_STATE_PARTIAL : -/* -* Require frequent reseeds until the seed source is -* fully initialized. -*/ - drbg->reseed_threshold =50 ; -break ; - -case DRBG_SEED_STATE_FULL : -/* -* Seed source has become fully initialized, frequent -* reseeds no longer required. -*/ - drbg->reseed_threshold =DRBG_MAX_REQUESTS ; -break ; - } -} - -static void drbg_seed_from_random (struct drbg_state *drbg) - __must_hold(&drbg->drbg_mutex) -{ -u8 entropy[DRBG_SEC_STRENGTH ]; - -get_random_bytes (entropy,DRBG_SEC_STRENGTH ); - -__drbg_seed (drbg, entropy,DRBG_SEC_STRENGTH ,NULL ,0 , -DRBG_SEED_STATE_FULL ); - -memzero_explicit (entropy,DRBG_SEC_STRENGTH ); -} - -static bool drbg_nopr_reseed_interval_elapsed (struct drbg_state *drbg) -{ -unsigned long next_reseed; - -/* Don't ever reseed from get_random_bytes() in test mode. */ -if (drbg->test_entropylen) -return false; - -/* -* Obtain fresh entropy for the nopr DRBGs after 300s have -* elapsed in order to still achieve sort of partial -* prediction resistance over the time domain at least. Note -* that the period of 300s has been chosen to match the -* CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha -* rngs. -*/ - next_reseed = drbg->last_seed_time +300 *HZ ; -return time_after (jiffies, next_reseed); -} -/* * Seeding or reseeding of the DRBG * * @drbg: DRBG state struct * @pers: personalization / additional information buffer
@@ -323,11 +247,10 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, {int ret;u8 entropy_buf[(32 +16 ) *2 ];size_t entropylen;const u8 *entropy; -enum drbg_seed_state new_seed_state =DRBG_SEED_STATE_FULL ;/* 9.1 / 9.2 / 9.3.1 step 3 */ if (pers_len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: personalization string too long %zu\n" , pers_len);
@@ -353,13 +276,10 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len,else entropylen =DRBG_SEC_STRENGTH ;BUG_ON (entropylen *2 >sizeof (entropy_buf));/* Get seed from in-kernel /dev/urandom */ -if (!rng_is_initialized ()) - new_seed_state =DRBG_SEED_STATE_PARTIAL ; -get_random_bytes (entropy_buf, entropylen);if (!drbg->jent) {pr_devel ("DRBG: (re)seeding with %zu bytes of entropy\n" , entropylen);
@@ -399,11 +319,12 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, }if (pers_len)pr_devel ("DRBG: using personalization string\n" ); -__drbg_seed (drbg, entropy, entropylen, pers, pers_len, new_seed_state); +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;
@@ -461,31 +382,25 @@ static int drbg_generate(struct drbg_state *drbg,/* 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_threshold < drbg->reseed_ctr) - drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; - -if (drbg->pr || drbg->seeded ==DRBG_SEED_STATE_UNSEEDED ) { -pr_devel ("DRBG: reseeding before generation (prediction " -"resistance: %s, state %s)\n" , -str_true_false (drbg->pr), - (drbg->seeded ==DRBG_SEED_STATE_FULL ? -"seeded" :"unseeded" )); +if (drbg->pr || drbg->reseed_ctr >DRBG_MAX_REQUESTS ) { +pr_devel ("DRBG: reseeding before generation (prediction resistance: %s)\n" , +str_true_false (drbg->pr));/* 9.3.1 steps 7.1 through 7.3 */ len =drbg_seed (drbg, addtl, addtl_len, true);if (len) goto err;/* 9.3.1 step 7.4 */ addtl =NULL ; addtl_len =0 ; - }else if (rng_is_initialized () && - (drbg->seeded ==DRBG_SEED_STATE_PARTIAL || -drbg_nopr_reseed_interval_elapsed (drbg))) { -drbg_seed_from_random (drbg); }/* 9.3.1 step 8 and 10 */ drbg_hmac_generate (drbg, buf, buflen, addtl, addtl_len);
@@ -562,13 +477,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,*/ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ drbg->pr = pr; - drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; - drbg->last_seed_time =0 ; - drbg->reseed_threshold =DRBG_MAX_REQUESTS ;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 ) {
@@ -671,11 +583,10 @@ static inline int __init drbg_healthcheck_sanity(void)if (!drbg)return -ENOMEM ;guard (mutex_init)(&drbg->drbg_mutex); drbg->instantiated = true; - drbg->reseed_threshold =DRBG_MAX_REQUESTS ;/* * 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
Signature · 1 line
2.53.0
Re: [PATCH 36/38] crypto: drbg - Remove redundant reseeding based on random.c state
Hi Eric,
Quoted 9 lines · Eric Biggers
We're now incorporating 32 bytes from
get_random_bytes()in the additional input string on every request. The additional input string is processed with a call todrbg_hmac_update(), which is exactly how the seed is processed. Thus, in reality this is as good as a reseed.From the perspective of FIPS 140-3, it isn't as good as a reseed. But
it doesn't actually matter, because from FIPS's point of viewget_random_bytes()provides zero entropy anyway.
Quoted 6 lines
Thus, neither the reseed with more
get_random_bytes()every 300s, nor the logic that reseeds more frequently beforerng_is_initialized(), is actually needed anymore. Remove it to simplify the code significantly.(Technically the use of
get_random_bytes()indrbg_seed()itself could be removed too. But it's safer to keep it there for now.)
It's fair to say that the additional input is as good as a reseed (if FIPS is not considered), but then is there any reason to keep get_random_bytes() in drbg_seed()? You say it could be removed but it's safer to keep it there for now? In what way is it safer? The additional input is mixed into the HMAC_DRBG state prior to generating random bits, so should already provide sufficient assurance that the generated bits incorporate the output of get_random_bytes()?
Quoted 229 lines
Signed-off-by Eric Biggers <[email protected]>--- crypto/drbg.c | 107 +++++--------------------------------------------- 1 file changed, 9 insertions(+), 98 deletions(-)crypto/drbg.c +9
-98@@ -91,22 +91,15 @@#include <crypto/internal/rng.h> #include <crypto/sha2.h> #include <linux/fips.h> #include <linux/kernel.h> -#include <linux/jiffies.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/string_choices.h> #include <linux/unaligned.h> -enum drbg_seed_state { -DRBG_SEED_STATE_UNSEEDED , -DRBG_SEED_STATE_PARTIAL ,/* Seeded with !rng_is_initialized() */ -DRBG_SEED_STATE_FULL , -}; -/* State length in bytes */ #define DRBG_STATE_LEN SHA512_DIGEST_SIZE/* Security strength in bytes */ #define DRBG_SEC_STRENGTH (SHA512_DIGEST_SIZE / 2)@@ -135,13 +128,10 @@ 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; -size_t reseed_threshold; -enum drbg_seed_state seeded;/* DRBG fully seeded? */ -unsigned long last_seed_time;bool instantiated;bool pr;/* Prediction resistance enabled? */ struct crypto_rng *jent;const u8 *test_entropy;size_t test_entropylen;@@ -237,76 +227,10 @@ static void drbg_hmac_generate(struct drbg_state *drbg,drbg_hmac_update (drbg, addtl1, addtl1_len, addtl2, addtl2_len);memzero_explicit (addtl2,sizeof (addtl2)); } -static inline void __drbg_seed (struct drbg_state *drbg, -const u8 *seed1,size_t seed1_len, -const u8 *seed2,size_t seed2_len, -enum drbg_seed_state new_seed_state) -{ -drbg_hmac_update (drbg, seed1, seed1_len, seed2, seed2_len); - - drbg->seeded = new_seed_state; - drbg->last_seed_time = jiffies; - drbg->reseed_ctr =1 ; - -switch (drbg->seeded) { -case DRBG_SEED_STATE_UNSEEDED : -/* Impossible, but handle it to silence compiler warnings. */ - fallthrough; -case DRBG_SEED_STATE_PARTIAL : -/* -* Require frequent reseeds until the seed source is -* fully initialized. -*/ - drbg->reseed_threshold =50 ; -break ; - -case DRBG_SEED_STATE_FULL : -/* -* Seed source has become fully initialized, frequent -* reseeds no longer required. -*/ - drbg->reseed_threshold =DRBG_MAX_REQUESTS ; -break ; - } -} - -static void drbg_seed_from_random (struct drbg_state *drbg) - __must_hold(&drbg->drbg_mutex) -{ -u8 entropy[DRBG_SEC_STRENGTH ]; - -get_random_bytes (entropy,DRBG_SEC_STRENGTH ); - -__drbg_seed (drbg, entropy,DRBG_SEC_STRENGTH ,NULL ,0 , -DRBG_SEED_STATE_FULL ); - -memzero_explicit (entropy,DRBG_SEC_STRENGTH ); -} - -static bool drbg_nopr_reseed_interval_elapsed (struct drbg_state *drbg) -{ -unsigned long next_reseed; - -/* Don't ever reseed from get_random_bytes() in test mode. */ -if (drbg->test_entropylen) -return false; - -/* -* Obtain fresh entropy for the nopr DRBGs after 300s have -* elapsed in order to still achieve sort of partial -* prediction resistance over the time domain at least. Note -* that the period of 300s has been chosen to match the -* CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha -* rngs. -*/ - next_reseed = drbg->last_seed_time +300 *HZ ; -return time_after (jiffies, next_reseed); -} -/* * Seeding or reseeding of the DRBG * * @drbg: DRBG state struct * @pers: personalization / additional information buffer @@ -323,11 +247,10 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, {int ret;u8 entropy_buf[(32 +16 ) *2 ];size_t entropylen;const u8 *entropy; -enum drbg_seed_state new_seed_state =DRBG_SEED_STATE_FULL ;/* 9.1 / 9.2 / 9.3.1 step 3 */ if (pers_len >DRBG_MAX_ADDTL ) {pr_devel ("DRBG: personalization string too long %zu\n" , pers_len);@@ -353,13 +276,10 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len,else entropylen =DRBG_SEC_STRENGTH ;BUG_ON (entropylen *2 >sizeof (entropy_buf));/* Get seed from in-kernel /dev/urandom */ -if (!rng_is_initialized ()) - new_seed_state =DRBG_SEED_STATE_PARTIAL ; -get_random_bytes (entropy_buf, entropylen);if (!drbg->jent) {pr_devel ("DRBG: (re)seeding with %zu bytes of entropy\n" , entropylen);@@ -399,11 +319,12 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, }if (pers_len)pr_devel ("DRBG: using personalization string\n" ); -__drbg_seed (drbg, entropy, entropylen, pers, pers_len, new_seed_state); +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;@@ -461,31 +382,25 @@ static int drbg_generate(struct drbg_state *drbg,/* 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_threshold < drbg->reseed_ctr) - drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; - -if (drbg->pr || drbg->seeded ==DRBG_SEED_STATE_UNSEEDED ) { -pr_devel ("DRBG: reseeding before generation (prediction " -"resistance: %s, state %s)\n" , -str_true_false (drbg->pr), - (drbg->seeded ==DRBG_SEED_STATE_FULL ? -"seeded" :"unseeded" )); +if (drbg->pr || drbg->reseed_ctr >DRBG_MAX_REQUESTS ) { +pr_devel ("DRBG: reseeding before generation (prediction resistance: %s)\n" , +str_true_false (drbg->pr));/* 9.3.1 steps 7.1 through 7.3 */ len =drbg_seed (drbg, addtl, addtl_len, true);if (len) goto err;/* 9.3.1 step 7.4 */ addtl =NULL ; addtl_len =0 ; - }else if (rng_is_initialized () && - (drbg->seeded ==DRBG_SEED_STATE_PARTIAL || -drbg_nopr_reseed_interval_elapsed (drbg))) { -drbg_seed_from_random (drbg); }/* 9.3.1 step 8 and 10 */ drbg_hmac_generate (drbg, buf, buflen, addtl, addtl_len);@@ -562,13 +477,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,*/ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ drbg->pr = pr; - drbg->seeded =DRBG_SEED_STATE_UNSEEDED ; - drbg->last_seed_time =0 ; - drbg->reseed_threshold =DRBG_MAX_REQUESTS ;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 ) {@@ -671,11 +583,10 @@ static inline int __init drbg_healthcheck_sanity(void)if (!drbg)return -ENOMEM ;guard (mutex_init)(&drbg->drbg_mutex); drbg->instantiated = true; - drbg->reseed_threshold =DRBG_MAX_REQUESTS ;/* * 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
Re: [PATCH 36/38] crypto: drbg - Remove redundant reseeding based on random.c state
Quoted 18 lines · Joachim Vandersmissen
Hi Eric,
Quoted 9 lines · Eric Biggers
We're now incorporating 32 bytes from
get_random_bytes()in the additional input string on every request. The additional input string is processed with a call todrbg_hmac_update(), which is exactly how the seed is processed. Thus, in reality this is as good as a reseed.From the perspective of FIPS 140-3, it isn't as good as a reseed. But
it doesn't actually matter, because from FIPS's point of viewget_random_bytes()provides zero entropy anyway.Quoted 6 lines
Thus, neither the reseed with more
get_random_bytes()every 300s, nor the logic that reseeds more frequently beforerng_is_initialized(), is actually needed anymore. Remove it to simplify the code significantly.(Technically the use of
get_random_bytes()indrbg_seed()itself could be removed too. But it's safer to keep it there for now.)
Quoted 7 lines
It's fair to say that the additional input is as good as a reseed (if FIPS is not considered), but then is there any reason to keep
get_random_bytes()indrbg_seed()? You say it could be removed but it's safer to keep it there for now? In what way is it safer? The additional input is mixed into theHMAC_DRBGstate prior to generating random bits, so should already provide sufficient assurance that the generated bits incorporate the output ofget_random_bytes()?
I do agree that patch 34 makes the get_random_bytes() in drbg_seed() redundant too. I'm just not yet sure that removing it would strike the right balance between defense in depth and eliminating redundancy.
Keeping it there also keeps it very clear that whenever jitterentropy entropy is used, we're also using an equal number of bytes from get_random_bytes() alongside it. (Remember, not everyone "trusts" jitterentropy. People auditing this code might *really* want to see the get_random_bytes().) The additional input does achieve the get_random_bytes() integration anyway, just it's a bit more subtle.
- Eric
PATCH 37/38 crypto: drbg - Clean up generation code
In reply to Eric BiggersA few miscellaneous cleanups to make the code a bit more readable:
- Replace (buf, buflen) with (out, outlen)
- Update (out, outlen) as we go along
- Use size_t for lengths
- Use min()
- Adjust some comments and log messages
- Rename a variable named 'len' to 'err', since it isn't a length
--- crypto/drbg.c | 53 ++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-)
crypto/drbg.c +19 -34
@@ -178,16 +178,13 @@ static void drbg_hmac_update(struct drbg_state *drbg, }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, -unsigned char *buf, -unsigned int buflen, +static void drbg_hmac_generate (struct drbg_state *drbg,u8 *out,size_t outlen,const u8 *addtl1,size_t addtl1_len) { -int len =0 ;u8 addtl2[32 ];size_t addtl2_len =0 ;/* * Append some bytes from get_random_bytes() to the additional input
@@ -208,21 +205,20 @@ static void drbg_hmac_generate(struct drbg_state *drbg,/* 10.1.2.5 step 2 */ if (addtl1_len || addtl2_len)drbg_hmac_update (drbg, addtl1, addtl1_len, addtl2, addtl2_len); -while (len < buflen) { -unsigned int outlen =0 ; +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); - outlen = (DRBG_STATE_LEN < (buflen - len)) ? -DRBG_STATE_LEN : (buflen - len);/* 10.1.2.5 step 4.2 */ -memcpy (buf + len, drbg->V, outlen); - len += outlen; +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);
@@ -329,47 +325,42 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len,return ret; }/* -* DRBG generate function as required by SP800-90A - this function -* generates random numbers +* Generate random bytes from an SP800-90A DRBG. * * @drbg DRBG state handle -* @buf Buffer where to store the random numbers -- the buffer must already -* be pre-allocated by caller -* @buflen Length of output buffer - this value defines the number of random -* bytes pulled from DRBG +* @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, -unsigned char *buf,unsigned int buflen, +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 len =0 ; +int err;if (!drbg->instantiated) {pr_devel ("DRBG: not yet instantiated\n" );return -EINVAL ; } -if (0 == buflen || !buf) { +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 (buflen >DRBG_MAX_REQUEST_BYTES ) { -pr_devel ("DRBG: requested random numbers too large %u\n" , - buflen); +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 */
@@ -391,20 +382,20 @@ static int drbg_generate(struct drbg_state *drbg,*/ if (drbg->pr || drbg->reseed_ctr >DRBG_MAX_REQUESTS ) {pr_devel ("DRBG: reseeding before generation (prediction resistance: %s)\n" ,str_true_false (drbg->pr));/* 9.3.1 steps 7.1 through 7.3 */ - len =drbg_seed (drbg, addtl, addtl_len, true); -if (len) - goto err; + 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, buf, buflen, addtl, addtl_len); +drbg_hmac_generate (drbg, out, outlen, addtl, addtl_len);/* 10.1.2.5 step 7 */ drbg->reseed_ctr++;/*
@@ -418,17 +409,11 @@ static int drbg_generate(struct drbg_state *drbg,* 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. */ -/* -* All operations were successful, return 0 as mandated by -* the kernel crypto API interface. -*/ - len =0 ; -err: -return len; +return 0 ; }/*************************************************************** * Kernel crypto API interface to DRBG ***************************************************************/
Signature · 1 line
2.53.0
PATCH 38/38 crypto: drbg - Clean up loop in drbg_hmac_update()
In reply to Eric BiggersThis loop is a bit hard to read, with the loop counter that's used in the HMAC being separate from the actual loop counter, which counts backwards for some reason. Just replace it with a regular loop.
--- crypto/drbg.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-)
crypto/drbg.c +2 -12
@@ -135,37 +135,27 @@ struct drbg_state {struct crypto_rng *jent;const u8 *test_entropy;size_t test_entropylen; }; -enum drbg_prefixes { -DRBG_PREFIX0 =0x00 , -DRBG_PREFIX1 , -}; -/****************************************************************** * 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) { -int i =0 ;struct hmac_sha512_ctx hmac_ctx;u8 new_key[DRBG_STATE_LEN ]; -for (i =2 ;0 < i; i--) { -/* first round uses 0x0, second 0x1 */ -unsigned char prefix =DRBG_PREFIX0 ; -if (1 == i) - prefix =DRBG_PREFIX1 ; +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, &prefix,1 ); +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 );
Signature · 1 line
2.53.0
Herbert Xu
maintainerQuoted 129 lines · Eric Biggers
This series is intended to be taken through the cryptodev tree. It can also be retrieved from:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git drbg-v1
This series fixes and greatly simplifies
crypto/drbg.c, i.e. the kernel's implementation of NIST SP800-90A. This code isn't normally used, but it's sometimes used by people doing FIPS 140-3 certifications.Note: this series is *not* meant to encourage using this code over
random.c. In fact, my recent commit65b3c2f627851639made "normal" systems stop using this code. It's just that the reality is that this is in the kernel tree, it's been there for many years, and people are using it to get FIPS 140-3 certifications. As long as that's the case, it might as well be fixed up and simplified. Another reason to simplify this as much as possible is that for historical reasons it's accessible to unprivileged users viaAF_ALG(even though it shouldn't be). So I do think this is a clear step forwards, regardless of level of enthusiasm for FIPS, especially considering the massively negative diffstat.Patches 1-5 begin with some bug fixes. Fixes for
CTR_DRBGandHASH_DRBGare included, despite that code being removed later in the series, so that they can be backported (though that is likely unused code anyway).Patches 6-11 do some initial cleanups.
Patches 12-17 clean up the museum of DRBG variants to just support the HMAC-SHA512 DRBG only, dropping support for the others. This is already the default variant, it makes sense that it's the default, and it's probably the only one actually being used on current kernels. In any case, supporting more than one is pretty pointless. See the patches for more details about why it makes sense to keep using this one.
Patches 18-33 contain many more cleanups, including switching from the
crypto_shashAPI to the crypto library.Patch 34 is a significant one: it starts adding 32 bytes from
get_random_bytes()to every additional input string. This is to work around the forward secrecy bug described in Woodage & Shumow (2018)
(https://eprint.iacr.org/2018/349.pdf), and to ensure thatrandom.creseeds are actually reflected indrbg.c. Of course, for FIPS 140-3 this is irrelevant, but this is the right thing to do in practice, and it should makedrbg.cquite a bit more robust in practice. (This isn't particularly novel, either; BoringSSL does essentially this same thing.)Patches 35-38 are some further cleanups, including some tweaks to when the formal reseeding happens.
Note: while the primary goal of this series is to fix and simplify this code, this series is also intended to preserve the FIPS 140-3 "certifiable" property of
crypto/drbg.c. I.e. after this series, it should still be possible to get a FIPS 140-3 certification that covers it. In fact it should become quite a bit easier, since there will be only one DRBG variant to worry about and the code will be much more straightforward. If there's anything I missed, let me know.Eric Biggers (38):
crypto: drbg - Fix returning success on failure inCTR_DRBG
crypto: drbg - Fix misaligned writes inCTR_DRBGandHASH_DRBG
crypto: drbg - Fix ineffective sanity check
crypto: drbg - Fixdrbg_max_addtl()on 64-bit kernels
crypto: drbg - Fix thefips_enabledpriority boost
crypto: drbg - Remove always-enabled symbolCRYPTO_DRBG_HMAC
crypto: drbg - Remove broken commented-out code
crypto: drbg - Remove unhelpful helper functions
crypto: drbg - Remove obsolete FIPS 140-2 continuous test
crypto: drbg - Foldinclude/crypto/drbg.hintocrypto/drbg.c
crypto: drbg - Remove import ofcrypto_cipherfunctions
crypto: drbg - Remove support forCTR_DRBG
crypto: drbg - Remove support forHASH_DRBG
crypto: drbg - Flatten the DRBG menu
crypto: testmgr - Add test fordrbg_pr_hmac_sha512
crypto: testmgr - Update test fordrbg_nopr_hmac_sha512
crypto: drbg - Remove support for HMAC-SHA256 and HMAC-SHA384
crypto: drbg - Simplify algorithm registration
crypto: drbg - De-virtualizedrbg_state_ops
crypto: drbg - Move fixed values into constants
crypto: drbg - Embed V and C into structdrbg_state
crypto: drbg - Use HMAC-SHA512 library API
crypto: drbg - Removedrbg_core
crypto: drbg - Install separate seed functions for pr and nopr
crypto: drbg - Move module aliases to end of file
crypto: drbg - Consolidate "instantiate" logic and remove
drbg_state::C
crypto: drbg - Eliminate use of 'drbg_string' and lists
crypto: drbg - Simplifydrbg_generate_long()and fold into caller
crypto: drbg - Putrng_algmethods in logical order
crypto: drbg - Folddrbg_instantiate()intodrbg_kcapi_seed()
crypto: drbg - Separate "reseed" case indrbg_kcapi_seed()
crypto: drbg - Folddrbg_prepare_hrng()intodrbg_kcapi_seed()
crypto: drbg - Simplify "uninstantiate" logic
crypto: drbg - Includeget_random_bytes()output in additional input
crypto: drbg - ChangeDRBG_MAX_REQUESTSto 4096
crypto: drbg - Remove redundant reseeding based onrandom.cstate
crypto: drbg - Clean up generation code
crypto: drbg - Clean up loop indrbg_hmac_update()Documentation/crypto/api-samples.rst | 2 +- Documentation/crypto/userspace-if.rst | 2 +- arch/m68k/configs/amiga_defconfig | 2 - arch/m68k/configs/apollo_defconfig | 2 - arch/m68k/configs/atari_defconfig | 2 - arch/m68k/configs/bvme6000_defconfig | 2 - arch/m68k/configs/hp300_defconfig | 2 - arch/m68k/configs/mac_defconfig | 2 - arch/m68k/configs/multi_defconfig | 2 - arch/m68k/configs/mvme147_defconfig | 2 - arch/m68k/configs/mvme16x_defconfig | 2 - arch/m68k/configs/q40_defconfig | 2 - arch/m68k/configs/sun3_defconfig | 2 - arch/m68k/configs/sun3x_defconfig | 2 - arch/mips/configs/decstation_64_defconfig | 2 - arch/mips/configs/decstation_defconfig | 2 - arch/mips/configs/decstation_r4k_defconfig | 2 - crypto/Kconfig | 40 +- crypto/df_sp80090a.c | 8 +- crypto/drbg.c | 1800 +++-------------- crypto/testmgr.c | 143 +- crypto/testmgr.h | 1262 ++++-------- drivers/crypto/xilinx/xilinx-trng.c | 1 - include/crypto/df_sp80090a.h | 25 + include/crypto/drbg.h | 263 --- include/crypto/internal/drbg.h | 54 - .../crypto/chacha20-s390/test-cipher.c | 1 - 27 files changed, 728 insertions(+), 2903 deletions(-) delete mode 100644 include/crypto/drbg.h delete mode 100644 include/crypto/internal/drbg.h
Quoted 3 lines
base-commit:
c1f49dea2b8f335813d3b348fd39117fb8efb428Signature · 1 line
2.53.0
All 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