diff options
Diffstat (limited to 'crypto/drbg.c')
-rw-r--r-- | crypto/drbg.c | 257 |
1 files changed, 115 insertions, 142 deletions
diff --git a/crypto/drbg.c b/crypto/drbg.c index a53ee099..d748a1d0 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -98,6 +98,7 @@ */ #include <crypto/drbg.h> +#include <linux/string.h> /*************************************************************** * Backend cipher definitions available to DRBG @@ -117,27 +118,18 @@ static const struct drbg_core drbg_cores[] = { { .flags = DRBG_CTR | DRBG_STRENGTH128, .statelen = 32, /* 256 bits as defined in 10.2.1 */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 16, .cra_name = "ctr_aes128", .backend_cra_name = "ecb(aes)", }, { .flags = DRBG_CTR | DRBG_STRENGTH192, .statelen = 40, /* 320 bits as defined in 10.2.1 */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 16, .cra_name = "ctr_aes192", .backend_cra_name = "ecb(aes)", }, { .flags = DRBG_CTR | DRBG_STRENGTH256, .statelen = 48, /* 384 bits as defined in 10.2.1 */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 16, .cra_name = "ctr_aes256", .backend_cra_name = "ecb(aes)", @@ -147,36 +139,24 @@ static const struct drbg_core drbg_cores[] = { { .flags = DRBG_HASH | DRBG_STRENGTH128, .statelen = 55, /* 440 bits */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 20, .cra_name = "sha1", .backend_cra_name = "sha1", }, { .flags = DRBG_HASH | DRBG_STRENGTH256, .statelen = 111, /* 888 bits */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 48, .cra_name = "sha384", .backend_cra_name = "sha384", }, { .flags = DRBG_HASH | DRBG_STRENGTH256, .statelen = 111, /* 888 bits */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 64, .cra_name = "sha512", .backend_cra_name = "sha512", }, { .flags = DRBG_HASH | DRBG_STRENGTH256, .statelen = 55, /* 440 bits */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 32, .cra_name = "sha256", .backend_cra_name = "sha256", @@ -186,36 +166,24 @@ static const struct drbg_core drbg_cores[] = { { .flags = DRBG_HMAC | DRBG_STRENGTH128, .statelen = 20, /* block length of cipher */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 20, .cra_name = "hmac_sha1", .backend_cra_name = "hmac(sha1)", }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 48, .cra_name = "hmac_sha384", .backend_cra_name = "hmac(sha384)", }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 64, /* block length of cipher */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 64, .cra_name = "hmac_sha512", .backend_cra_name = "hmac(sha512)", }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 32, /* block length of cipher */ - .max_addtllen = 35, - .max_bits = 19, - .max_req = 48, .blocklen_bytes = 32, .cra_name = "hmac_sha256", .backend_cra_name = "hmac(sha256)", @@ -302,52 +270,19 @@ static bool drbg_fips_continuous_test(struct drbg_state *drbg, * Convert an integer into a byte representation of this integer. * The byte representation is big-endian * - * @buf buffer holding the converted integer * @val value to be converted - * @buflen length of buffer + * @buf buffer holding the converted integer -- caller must ensure that + * buffer size is at least 32 bit */ #if (defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR)) -static inline void drbg_int2byte(unsigned char *buf, uint64_t val, - size_t buflen) +static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf) { - unsigned char *byte; - uint64_t i; + struct s { + __be32 conv; + }; + struct s *conversion = (struct s *) buf; - byte = buf + (buflen - 1); - for (i = 0; i < buflen; i++) - *(byte--) = val >> (i * 8) & 0xff; -} - -/* - * Increment buffer - * - * @dst buffer to increment - * @add value to add - */ -static inline void drbg_add_buf(unsigned char *dst, size_t dstlen, - const unsigned char *add, size_t addlen) -{ - /* implied: dstlen > addlen */ - unsigned char *dstptr; - const unsigned char *addptr; - unsigned int remainder = 0; - size_t len = addlen; - - dstptr = dst + (dstlen-1); - addptr = add + (addlen-1); - while (len) { - remainder += *dstptr + *addptr; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; addptr--; - } - len = dstlen - addlen; - while (len && remainder > 0) { - remainder = *dstptr + 1; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; - } + conversion->conv = cpu_to_be32(val); } #endif /* defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR) */ @@ -357,6 +292,13 @@ static inline void drbg_add_buf(unsigned char *dst, size_t dstlen, #ifdef CONFIG_CRYPTO_DRBG_CTR #define CRYPTO_DRBG_CTR_STRING "CTR " +MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes256"); +MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes256"); +MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes192"); +MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192"); +MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128"); +MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128"); + static int drbg_kcapi_sym(struct drbg_state *drbg, const unsigned char *key, unsigned char *outval, const struct drbg_string *in); static int drbg_init_sym_kernel(struct drbg_state *drbg); @@ -483,10 +425,10 @@ static int drbg_ctr_df(struct drbg_state *drbg, /* 10.4.2 step 2 -- calculate the entire length of all input data */ list_for_each_entry(seed, seedlist, list) inputlen += seed->len; - drbg_int2byte(&L_N[0], inputlen, 4); + drbg_cpu_to_be32(inputlen, &L_N[0]); /* 10.4.2 step 3 */ - drbg_int2byte(&L_N[4], bytes_to_return, 4); + drbg_cpu_to_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) % (drbg_blocklen(drbg)); @@ -517,7 +459,7 @@ static int drbg_ctr_df(struct drbg_state *drbg, * holds zeros after allocation -- even the increment of i * is irrelevant as the increment remains within length of i */ - drbg_int2byte(iv, i, 4); + drbg_cpu_to_be32(i, iv); /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ ret = drbg_ctr_bcc(drbg, temp + templen, K, &bcc_list); if (ret) @@ -556,9 +498,9 @@ static int drbg_ctr_df(struct drbg_state *drbg, ret = 0; out: - memset(iv, 0, drbg_blocklen(drbg)); - memset(temp, 0, drbg_statelen(drbg)); - memset(pad, 0, drbg_blocklen(drbg)); + memzero_explicit(iv, drbg_blocklen(drbg)); + memzero_explicit(temp, drbg_statelen(drbg)); + memzero_explicit(pad, drbg_blocklen(drbg)); return ret; } @@ -588,7 +530,6 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, unsigned char *temp_p, *df_data_p; /* pointer to iterate over buffers */ unsigned int len = 0; struct drbg_string cipherin; - unsigned char prefix = DRBG_PREFIX1; memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); if (3 > reseed) @@ -608,7 +549,7 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, */ while (len < (drbg_statelen(drbg))) { /* 10.2.1.2 step 2.1 */ - drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1); + crypto_inc(drbg->V, drbg_blocklen(drbg)); /* * 10.2.1.2 step 2.2 */ ret = drbg_kcapi_sym(drbg, drbg->C, temp + len, &cipherin); @@ -633,9 +574,9 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, ret = 0; out: - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); + memzero_explicit(temp, drbg_statelen(drbg) + drbg_blocklen(drbg)); if (2 != reseed) - memset(df_data, 0, drbg_statelen(drbg)); + memzero_explicit(df_data, drbg_statelen(drbg)); return ret; } @@ -651,7 +592,6 @@ static int drbg_ctr_generate(struct drbg_state *drbg, int len = 0; int ret = 0; struct drbg_string data; - unsigned char prefix = DRBG_PREFIX1; memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); @@ -663,7 +603,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg, } /* 10.2.1.5.2 step 4.1 */ - drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1); + crypto_inc(drbg->V, drbg_blocklen(drbg)); drbg_string_fill(&data, drbg->V, drbg_blocklen(drbg)); while (len < buflen) { int outlen = 0; @@ -677,7 +617,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg, drbg_blocklen(drbg) : (buflen - len); if (!drbg_fips_continuous_test(drbg, drbg->scratchpad)) { /* 10.2.1.5.2 step 6 */ - drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1); + crypto_inc(drbg->V, drbg_blocklen(drbg)); continue; } /* 10.2.1.5.2 step 4.3 */ @@ -685,7 +625,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg, len += outlen; /* 10.2.1.5.2 step 6 */ if (len < buflen) - drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1); + crypto_inc(drbg->V, drbg_blocklen(drbg)); } /* 10.2.1.5.2 step 6 */ @@ -694,7 +634,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg, len = ret; out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); + memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg)); return len; } @@ -719,6 +659,15 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg); #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"); +MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); +MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); +MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1"); +MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1"); + /* 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) @@ -729,11 +678,9 @@ 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(drbg->C, 0, drbg_statelen(drbg)); + if (!reseed) + /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ memset(drbg->V, 1, drbg_statelen(drbg)); - } drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg)); list_add_tail(&seed1.list, &seedlist); @@ -832,6 +779,47 @@ static struct drbg_state_ops drbg_hmac_ops = { #ifdef CONFIG_CRYPTO_DRBG_HASH #define CRYPTO_DRBG_HASH_STRING "HASH " +MODULE_ALIAS_CRYPTO("drbg_pr_sha512"); +MODULE_ALIAS_CRYPTO("drbg_nopr_sha512"); +MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); +MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); +MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); +MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); +MODULE_ALIAS_CRYPTO("drbg_pr_sha1"); +MODULE_ALIAS_CRYPTO("drbg_nopr_sha1"); + +/* + * Increment buffer + * + * @dst buffer to increment + * @add value to add + */ +static inline void drbg_add_buf(unsigned char *dst, size_t dstlen, + const unsigned char *add, size_t addlen) +{ + /* implied: dstlen > addlen */ + unsigned char *dstptr; + const unsigned char *addptr; + unsigned int remainder = 0; + size_t len = addlen; + + dstptr = dst + (dstlen-1); + addptr = add + (addlen-1); + while (len) { + remainder += *dstptr + *addptr; + *dstptr = remainder & 0xff; + remainder >>= 8; + len--; dstptr--; addptr--; + } + len = dstlen - addlen; + while (len && remainder > 0) { + remainder = *dstptr + 1; + *dstptr = remainder & 0xff; + remainder >>= 8; + len--; dstptr--; + } +} + /* * scratchpad usage: as drbg_hash_update and drbg_hash_df are used * interlinked, the scratchpad is used as follows: @@ -862,7 +850,7 @@ static int drbg_hash_df(struct drbg_state *drbg, /* 10.4.1 step 3 */ input[0] = 1; - drbg_int2byte(&input[1], (outlen * 8), 4); + drbg_cpu_to_be32((outlen * 8), &input[1]); /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ drbg_string_fill(&data, input, 5); @@ -884,7 +872,7 @@ static int drbg_hash_df(struct drbg_state *drbg, } out: - memset(tmp, 0, drbg_blocklen(drbg)); + memzero_explicit(tmp, drbg_blocklen(drbg)); return ret; } @@ -928,7 +916,7 @@ static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed, ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2); out: - memset(drbg->scratchpad, 0, drbg_statelen(drbg)); + memzero_explicit(drbg->scratchpad, drbg_statelen(drbg)); return ret; } @@ -963,7 +951,7 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg, drbg->scratchpad, drbg_blocklen(drbg)); out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); + memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg)); return ret; } @@ -978,7 +966,6 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg); struct drbg_string data; LIST_HEAD(datalist); - unsigned char prefix = DRBG_PREFIX1; memset(src, 0, drbg_statelen(drbg)); memset(dst, 0, drbg_blocklen(drbg)); @@ -999,7 +986,7 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, outlen = (drbg_blocklen(drbg) < (buflen - len)) ? drbg_blocklen(drbg) : (buflen - len); if (!drbg_fips_continuous_test(drbg, dst)) { - drbg_add_buf(src, drbg_statelen(drbg), &prefix, 1); + crypto_inc(src, drbg_statelen(drbg)); continue; } /* 10.1.1.4 step hashgen 4.2 */ @@ -1007,11 +994,11 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, len += outlen; /* 10.1.1.4 hashgen step 4.3 */ if (len < buflen) - drbg_add_buf(src, drbg_statelen(drbg), &prefix, 1); + crypto_inc(src, drbg_statelen(drbg)); } out: - memset(drbg->scratchpad, 0, + memzero_explicit(drbg->scratchpad, (drbg_statelen(drbg) + drbg_blocklen(drbg))); return len; } @@ -1023,7 +1010,10 @@ static int drbg_hash_generate(struct drbg_state *drbg, { int len = 0; int ret = 0; - unsigned char req[8]; + union { + unsigned char req[8]; + __be64 req_int; + } u; unsigned char prefix = DRBG_PREFIX3; struct drbg_string data1, data2; LIST_HEAD(datalist); @@ -1053,11 +1043,11 @@ static int drbg_hash_generate(struct drbg_state *drbg, drbg->scratchpad, drbg_blocklen(drbg)); drbg_add_buf(drbg->V, drbg_statelen(drbg), drbg->C, drbg_statelen(drbg)); - drbg_int2byte(req, drbg->reseed_ctr, sizeof(req)); - drbg_add_buf(drbg->V, drbg_statelen(drbg), req, 8); + u.req_int = cpu_to_be64(drbg->reseed_ctr); + drbg_add_buf(drbg->V, drbg_statelen(drbg), u.req, 8); out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); + memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg)); return len; } @@ -1142,6 +1132,11 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, pr_devel("DRBG: using personalization string\n"); } + if (!reseed) { + memset(drbg->V, 0, drbg_statelen(drbg)); + memset(drbg->C, 0, drbg_statelen(drbg)); + } + ret = drbg->d_ops->update(drbg, &seedlist, reseed); if (ret) goto out; @@ -1151,8 +1146,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, drbg->reseed_ctr = 1; out: - if (entropy) - kzfree(entropy); + kzfree(entropy); return ret; } @@ -1161,19 +1155,15 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; - if (drbg->V) - kzfree(drbg->V); + kzfree(drbg->V); drbg->V = NULL; - if (drbg->C) - kzfree(drbg->C); + kzfree(drbg->C); drbg->C = NULL; - if (drbg->scratchpad) - kzfree(drbg->scratchpad); + kzfree(drbg->scratchpad); drbg->scratchpad = NULL; drbg->reseed_ctr = 0; #ifdef CONFIG_CRYPTO_FIPS - if (drbg->prev) - kzfree(drbg->prev); + kzfree(drbg->prev); drbg->prev = NULL; drbg->fips_primed = false; #endif @@ -1188,17 +1178,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) int ret = -ENOMEM; unsigned int sb_size = 0; - if (!drbg) - return -EINVAL; - - drbg->V = kzalloc(drbg_statelen(drbg), GFP_KERNEL); + drbg->V = kmalloc(drbg_statelen(drbg), GFP_KERNEL); if (!drbg->V) goto err; - drbg->C = kzalloc(drbg_statelen(drbg), GFP_KERNEL); + drbg->C = kmalloc(drbg_statelen(drbg), GFP_KERNEL); if (!drbg->C) goto err; #ifdef CONFIG_CRYPTO_FIPS - drbg->prev = kzalloc(drbg_blocklen(drbg), GFP_KERNEL); + drbg->prev = kmalloc(drbg_blocklen(drbg), GFP_KERNEL); if (!drbg->prev) goto err; drbg->fips_primed = false; @@ -1263,15 +1250,6 @@ static int drbg_make_shadow(struct drbg_state *drbg, struct drbg_state **shadow) int ret = -ENOMEM; struct drbg_state *tmp = NULL; - if (!drbg || !drbg->core || !drbg->V || !drbg->C) { - pr_devel("DRBG: attempt to generate shadow copy for " - "uninitialized DRBG state rejected\n"); - return -EINVAL; - } - /* HMAC does not have a scratchpad */ - if (!(drbg->core->flags & DRBG_HMAC) && NULL == drbg->scratchpad) - return -EINVAL; - tmp = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); if (!tmp) return -ENOMEM; @@ -1293,8 +1271,7 @@ static int drbg_make_shadow(struct drbg_state *drbg, struct drbg_state **shadow) return 0; err: - if (tmp) - kzfree(tmp); + kzfree(tmp); return ret; } @@ -1385,11 +1362,9 @@ static int drbg_generate(struct drbg_state *drbg, shadow->seeded = false; /* allocate cipher handle */ - if (shadow->d_ops->crypto_init) { - len = shadow->d_ops->crypto_init(shadow); - if (len) - goto err; - } + len = shadow->d_ops->crypto_init(shadow); + if (len) + goto err; if (shadow->pr || !shadow->seeded) { pr_devel("DRBG: reseeding before generation (prediction " @@ -1471,8 +1446,7 @@ static int drbg_generate(struct drbg_state *drbg, #endif err: - if (shadow->d_ops->crypto_fini) - shadow->d_ops->crypto_fini(shadow); + shadow->d_ops->crypto_fini(shadow); drbg_restore_shadow(drbg, &shadow); return len; } @@ -1566,11 +1540,10 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, return ret; ret = -EFAULT; - if (drbg->d_ops->crypto_init && drbg->d_ops->crypto_init(drbg)) + if (drbg->d_ops->crypto_init(drbg)) goto err; ret = drbg_seed(drbg, pers, false); - if (drbg->d_ops->crypto_fini) - drbg->d_ops->crypto_fini(drbg); + drbg->d_ops->crypto_fini(drbg); if (ret) goto err; |