| // SPDX-License-Identifier: GPL-2.0 |
| |
| /* |
| * NIST SP800-90A DRBG derivation function |
| * |
| * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de> |
| */ |
| |
| #include <linux/errno.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/string.h> |
| #include <crypto/aes.h> |
| #include <crypto/df_sp80090a.h> |
| #include <crypto/internal/drbg.h> |
| |
| static void drbg_kcapi_symsetkey(struct crypto_aes_ctx *aesctx, |
| const unsigned char *key, |
| u8 keylen); |
| static void drbg_kcapi_symsetkey(struct crypto_aes_ctx *aesctx, |
| const unsigned char *key, u8 keylen) |
| { |
| aes_expandkey(aesctx, key, keylen); |
| } |
| |
| static void drbg_kcapi_sym(struct crypto_aes_ctx *aesctx, |
| unsigned char *outval, |
| const struct drbg_string *in, u8 blocklen_bytes) |
| { |
| /* there is only component in *in */ |
| BUG_ON(in->len < blocklen_bytes); |
| aes_encrypt(aesctx, outval, in->buf); |
| } |
| |
| /* BCC function for CTR DRBG as defined in 10.4.3 */ |
| |
| static void drbg_ctr_bcc(struct crypto_aes_ctx *aesctx, |
| unsigned char *out, const unsigned char *key, |
| struct list_head *in, |
| u8 blocklen_bytes, |
| u8 keylen) |
| { |
| struct drbg_string *curr = NULL; |
| struct drbg_string data; |
| short cnt = 0; |
| |
| drbg_string_fill(&data, out, blocklen_bytes); |
| |
| /* 10.4.3 step 2 / 4 */ |
| drbg_kcapi_symsetkey(aesctx, key, keylen); |
| 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 (blocklen_bytes == cnt) { |
| cnt = 0; |
| drbg_kcapi_sym(aesctx, out, &data, blocklen_bytes); |
| } |
| out[cnt] ^= *pos; |
| pos++; |
| cnt++; |
| len--; |
| } |
| } |
| /* 10.4.3 step 4.2 for last block */ |
| if (cnt) |
| drbg_kcapi_sym(aesctx, out, &data, blocklen_bytes); |
| } |
| |
| /* |
| * scratchpad usage: drbg_ctr_update is interlinked with crypto_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) |
| * |
| * crypto_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. |
| * refer to crypto_drbg_ctr_df_datalen() to get required length |
| */ |
| |
| /* Derivation Function for CTR DRBG as defined in 10.4.2 */ |
| int crypto_drbg_ctr_df(struct crypto_aes_ctx *aesctx, |
| unsigned char *df_data, size_t bytes_to_return, |
| struct list_head *seedlist, |
| u8 blocklen_bytes, |
| u8 statelen) |
| { |
| unsigned char L_N[8]; |
| /* S3 is input */ |
| struct drbg_string S1, S2, S4, cipherin; |
| LIST_HEAD(bcc_list); |
| unsigned char *pad = df_data + statelen; |
| unsigned char *iv = pad + blocklen_bytes; |
| unsigned char *temp = iv + blocklen_bytes; |
| 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; |
| u8 keylen; |
| |
| memset(pad, 0, blocklen_bytes); |
| memset(iv, 0, blocklen_bytes); |
| keylen = statelen - blocklen_bytes; |
| /* 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) % (blocklen_bytes); |
| /* wrap the padlen appropriately */ |
| if (padlen) |
| padlen = blocklen_bytes - 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, blocklen_bytes); |
| 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 < (keylen + (blocklen_bytes))) { |
| /* |
| * 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 */ |
| drbg_ctr_bcc(aesctx, temp + templen, K, &bcc_list, |
| blocklen_bytes, keylen); |
| /* 10.4.2 step 9.3 */ |
| i++; |
| templen += blocklen_bytes; |
| } |
| |
| /* 10.4.2 step 11 */ |
| X = temp + (keylen); |
| drbg_string_fill(&cipherin, X, blocklen_bytes); |
| |
| /* 10.4.2 step 12: overwriting of outval is implemented in next step */ |
| |
| /* 10.4.2 step 13 */ |
| drbg_kcapi_symsetkey(aesctx, temp, keylen); |
| 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 |
| */ |
| drbg_kcapi_sym(aesctx, X, &cipherin, blocklen_bytes); |
| blocklen = (blocklen_bytes < |
| (bytes_to_return - generated_len)) ? |
| blocklen_bytes : |
| (bytes_to_return - generated_len); |
| /* 10.4.2 step 13.2 and 14 */ |
| memcpy(df_data + generated_len, X, blocklen); |
| generated_len += blocklen; |
| } |
| |
| memset(iv, 0, blocklen_bytes); |
| memset(temp, 0, statelen + blocklen_bytes); |
| memset(pad, 0, blocklen_bytes); |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(crypto_drbg_ctr_df); |
| |
| MODULE_IMPORT_NS("CRYPTO_INTERNAL"); |
| MODULE_LICENSE("GPL v2"); |
| MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); |
| MODULE_DESCRIPTION("Derivation Function conformant to SP800-90A"); |