diff options
Diffstat (limited to 'crypto/drbg.c')
| -rw-r--r-- | crypto/drbg.c | 266 |
1 files changed, 13 insertions, 253 deletions
diff --git a/crypto/drbg.c b/crypto/drbg.c index dbe4c8bb5ceb..1d433dae9955 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -98,6 +98,7 @@ */ #include <crypto/drbg.h> +#include <crypto/df_sp80090a.h> #include <crypto/internal/cipher.h> #include <linux/kernel.h> #include <linux/jiffies.h> @@ -261,26 +262,6 @@ static int drbg_fips_continuous_test(struct drbg_state *drbg, return 0; } -/* - * 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 - */ -#if (defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR)) -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); -} -#endif /* defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR) */ - /****************************************************************** * CTR DRBG callback functions ******************************************************************/ @@ -294,10 +275,6 @@ MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192"); MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128"); MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128"); -static void drbg_kcapi_symsetkey(struct drbg_state *drbg, - const unsigned char *key); -static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval, - const struct drbg_string *in); static int drbg_init_sym_kernel(struct drbg_state *drbg); static int drbg_fini_sym_kernel(struct drbg_state *drbg); static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, @@ -305,202 +282,12 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, u8 *outbuf, u32 outlen); #define DRBG_OUTSCRATCHLEN 256 -/* BCC function for CTR DRBG as defined in 10.4.3 */ -static int drbg_ctr_bcc(struct drbg_state *drbg, - unsigned char *out, const unsigned char *key, - struct list_head *in) -{ - int ret = 0; - struct drbg_string *curr = NULL; - struct drbg_string data; - short cnt = 0; - - drbg_string_fill(&data, out, drbg_blocklen(drbg)); - - /* 10.4.3 step 2 / 4 */ - drbg_kcapi_symsetkey(drbg, key); - list_for_each_entry(curr, in, list) { - const unsigned char *pos = curr->buf; - size_t len = curr->len; - /* 10.4.3 step 4.1 */ - while (len) { - /* 10.4.3 step 4.2 */ - if (drbg_blocklen(drbg) == cnt) { - cnt = 0; - ret = drbg_kcapi_sym(drbg, out, &data); - if (ret) - return ret; - } - out[cnt] ^= *pos; - pos++; - cnt++; - len--; - } - } - /* 10.4.3 step 4.2 for last block */ - if (cnt) - ret = drbg_kcapi_sym(drbg, out, &data); - - return ret; -} - -/* - * scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df - * (and drbg_ctr_bcc, but this function does not need any temporary buffers), - * the scratchpad is used as follows: - * drbg_ctr_update: - * temp - * start: drbg->scratchpad - * length: drbg_statelen(drbg) + drbg_blocklen(drbg) - * note: the cipher writing into this variable works - * blocklen-wise. Now, when the statelen is not a multiple - * of blocklen, the generateion loop below "spills over" - * by at most blocklen. Thus, we need to give sufficient - * memory. - * df_data - * start: drbg->scratchpad + - * drbg_statelen(drbg) + drbg_blocklen(drbg) - * length: drbg_statelen(drbg) - * - * drbg_ctr_df: - * pad - * start: df_data + drbg_statelen(drbg) - * length: drbg_blocklen(drbg) - * iv - * start: pad + drbg_blocklen(drbg) - * length: drbg_blocklen(drbg) - * temp - * start: iv + drbg_blocklen(drbg) - * length: drbg_satelen(drbg) + drbg_blocklen(drbg) - * note: temp is the buffer that the BCC function operates - * on. BCC operates blockwise. drbg_statelen(drbg) - * is sufficient when the DRBG state length is a multiple - * of the block size. For AES192 (and maybe other ciphers) - * this is not correct and the length for temp is - * insufficient (yes, that also means for such ciphers, - * the final output of all BCC rounds are truncated). - * Therefore, add drbg_blocklen(drbg) to cover all - * possibilities. - */ - -/* Derivation Function for CTR DRBG as defined in 10.4.2 */ static int drbg_ctr_df(struct drbg_state *drbg, unsigned char *df_data, size_t bytes_to_return, struct list_head *seedlist) { - int ret = -EFAULT; - unsigned char L_N[8]; - /* S3 is input */ - struct drbg_string S1, S2, S4, cipherin; - LIST_HEAD(bcc_list); - unsigned char *pad = df_data + drbg_statelen(drbg); - unsigned char *iv = pad + drbg_blocklen(drbg); - unsigned char *temp = iv + drbg_blocklen(drbg); - size_t padlen = 0; - unsigned int templen = 0; - /* 10.4.2 step 7 */ - unsigned int i = 0; - /* 10.4.2 step 8 */ - const unsigned char *K = (unsigned char *) - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; - unsigned char *X; - size_t generated_len = 0; - size_t inputlen = 0; - struct drbg_string *seed = NULL; - - memset(pad, 0, drbg_blocklen(drbg)); - memset(iv, 0, drbg_blocklen(drbg)); - - /* 10.4.2 step 1 is implicit as we work byte-wise */ - - /* 10.4.2 step 2 */ - if ((512/8) < bytes_to_return) - 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]); - - /* 10.4.2 step 3 */ - 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)); - /* wrap the padlen appropriately */ - if (padlen) - padlen = drbg_blocklen(drbg) - padlen; - /* - * pad / padlen contains the 0x80 byte and the following zero bytes. - * As the calculated padlen value only covers the number of zero - * bytes, this value has to be incremented by one for the 0x80 byte. - */ - padlen++; - pad[0] = 0x80; - - /* 10.4.2 step 4 -- first fill the linked list and then order it */ - drbg_string_fill(&S1, iv, drbg_blocklen(drbg)); - list_add_tail(&S1.list, &bcc_list); - drbg_string_fill(&S2, L_N, sizeof(L_N)); - list_add_tail(&S2.list, &bcc_list); - list_splice_tail(seedlist, &bcc_list); - drbg_string_fill(&S4, pad, padlen); - list_add_tail(&S4.list, &bcc_list); - - /* 10.4.2 step 9 */ - while (templen < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) { - /* - * 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); - /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ - ret = drbg_ctr_bcc(drbg, temp + templen, K, &bcc_list); - if (ret) - goto out; - /* 10.4.2 step 9.3 */ - i++; - templen += drbg_blocklen(drbg); - } - - /* 10.4.2 step 11 */ - X = temp + (drbg_keylen(drbg)); - drbg_string_fill(&cipherin, X, drbg_blocklen(drbg)); - - /* 10.4.2 step 12: overwriting of outval is implemented in next step */ - - /* 10.4.2 step 13 */ - drbg_kcapi_symsetkey(drbg, temp); - while (generated_len < bytes_to_return) { - short blocklen = 0; - /* - * 10.4.2 step 13.1: the truncation of the key length is - * implicit as the key is only drbg_blocklen in size based on - * the implementation of the cipher function callback - */ - ret = drbg_kcapi_sym(drbg, X, &cipherin); - if (ret) - goto out; - blocklen = (drbg_blocklen(drbg) < - (bytes_to_return - generated_len)) ? - drbg_blocklen(drbg) : - (bytes_to_return - generated_len); - /* 10.4.2 step 13.2 and 14 */ - memcpy(df_data + generated_len, X, blocklen); - generated_len += blocklen; - } - - ret = 0; - -out: - memset(iv, 0, drbg_blocklen(drbg)); - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); - memset(pad, 0, drbg_blocklen(drbg)); - return ret; + return crypto_drbg_ctr_df(drbg->priv_data, df_data, drbg_statelen(drbg), + seedlist, drbg_blocklen(drbg), drbg_statelen(drbg)); } /* @@ -1310,10 +1097,8 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) sb_size = 0; else if (drbg->core->flags & DRBG_CTR) sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */ - drbg_statelen(drbg) + /* df_data */ - drbg_blocklen(drbg) + /* pad */ - drbg_blocklen(drbg) + /* iv */ - drbg_statelen(drbg) + drbg_blocklen(drbg); /* temp */ + crypto_drbg_ctr_df_datalen(drbg_statelen(drbg), + drbg_blocklen(drbg)); else sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg); @@ -1658,7 +1443,6 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, #if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC) struct sdesc { struct shash_desc shash; - char ctx[]; }; static int drbg_init_hash_kernel(struct drbg_state *drbg) @@ -1721,10 +1505,9 @@ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, #ifdef CONFIG_CRYPTO_DRBG_CTR static int drbg_fini_sym_kernel(struct drbg_state *drbg) { - struct crypto_cipher *tfm = - (struct crypto_cipher *)drbg->priv_data; - if (tfm) - crypto_free_cipher(tfm); + struct crypto_aes_ctx *aesctx = (struct crypto_aes_ctx *)drbg->priv_data; + + kfree(aesctx); drbg->priv_data = NULL; if (drbg->ctr_handle) @@ -1743,20 +1526,16 @@ static int drbg_fini_sym_kernel(struct drbg_state *drbg) static int drbg_init_sym_kernel(struct drbg_state *drbg) { - struct crypto_cipher *tfm; + struct crypto_aes_ctx *aesctx; struct crypto_skcipher *sk_tfm; struct skcipher_request *req; unsigned int alignmask; char ctr_name[CRYPTO_MAX_ALG_NAME]; - tfm = crypto_alloc_cipher(drbg->core->backend_cra_name, 0, 0); - if (IS_ERR(tfm)) { - pr_info("DRBG: could not allocate cipher TFM handle: %s\n", - drbg->core->backend_cra_name); - return PTR_ERR(tfm); - } - BUG_ON(drbg_blocklen(drbg) != crypto_cipher_blocksize(tfm)); - drbg->priv_data = tfm; + aesctx = kzalloc(sizeof(*aesctx), GFP_KERNEL); + if (!aesctx) + return -ENOMEM; + drbg->priv_data = aesctx; if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", drbg->core->backend_cra_name) >= CRYPTO_MAX_ALG_NAME) { @@ -1800,25 +1579,6 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg) return alignmask; } -static void drbg_kcapi_symsetkey(struct drbg_state *drbg, - const unsigned char *key) -{ - struct crypto_cipher *tfm = drbg->priv_data; - - crypto_cipher_setkey(tfm, key, (drbg_keylen(drbg))); -} - -static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval, - const struct drbg_string *in) -{ - struct crypto_cipher *tfm = drbg->priv_data; - - /* there is only component in *in */ - BUG_ON(in->len < drbg_blocklen(drbg)); - crypto_cipher_encrypt_one(tfm, outval, in->buf); - return 0; -} - static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, u8 *inbuf, u32 inlen, u8 *outbuf, u32 outlen) |
