mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512
This code is just trying to condition 48 bytes of random data. This can be done easily using HKDF-SHA512-Extract, saving 300 lines of code. This commit also fixes forward security (in this particular case) by clearing the entropy from memory after it's used. Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
@@ -1246,11 +1246,6 @@ config CRYPTO_KDF800108_CTR
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA256
|
||||
|
||||
config CRYPTO_DF80090A
|
||||
tristate
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CTR
|
||||
|
||||
endmenu
|
||||
menu "Userspace interface (deprecated)"
|
||||
|
||||
|
||||
@@ -208,6 +208,4 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
|
||||
#
|
||||
obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_DF80090A) += df_sp80090a.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_KRB5) += krb5/
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
// 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 <linux/unaligned.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/df_sp80090a.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 */
|
||||
BUG_ON(in->len < blocklen_bytes);
|
||||
aes_encrypt(aeskey, outval, in->buf);
|
||||
}
|
||||
|
||||
/* BCC function for CTR DRBG as defined in 10.4.3 */
|
||||
|
||||
static void drbg_ctr_bcc(struct aes_enckey *aeskey,
|
||||
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 */
|
||||
aes_prepareenckey(aeskey, 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(aeskey, out, &data, blocklen_bytes);
|
||||
}
|
||||
out[cnt] ^= *pos;
|
||||
pos++;
|
||||
cnt++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
/* 10.4.3 step 4.2 for last block */
|
||||
if (cnt)
|
||||
drbg_kcapi_sym(aeskey, 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 aes_enckey *aeskey,
|
||||
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;
|
||||
put_unaligned_be32(inputlen, &L_N[0]);
|
||||
|
||||
/* 10.4.2 step 3 */
|
||||
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)
|
||||
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
|
||||
*/
|
||||
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++;
|
||||
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 */
|
||||
aes_prepareenckey(aeskey, 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(aeskey, 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");
|
||||
Reference in New Issue
Block a user