mirror of https://github.com/torvalds/linux.git
crypto: drbg - Export CTR DRBG DF functions
Export drbg_ctr_df() derivative function to new module df_sp80090. Signed-off-by: Harsh Jain <h.jain@amd.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
3a86608788
commit
6c4fed5fee
|
|
@ -1205,8 +1205,7 @@ config CRYPTO_DRBG_HASH
|
||||||
|
|
||||||
config CRYPTO_DRBG_CTR
|
config CRYPTO_DRBG_CTR
|
||||||
bool "CTR_DRBG"
|
bool "CTR_DRBG"
|
||||||
select CRYPTO_AES
|
select CRYPTO_DF80090A
|
||||||
select CRYPTO_CTR
|
|
||||||
help
|
help
|
||||||
CTR_DRBG variant as defined in NIST SP800-90A.
|
CTR_DRBG variant as defined in NIST SP800-90A.
|
||||||
|
|
||||||
|
|
@ -1342,6 +1341,11 @@ config CRYPTO_KDF800108_CTR
|
||||||
select CRYPTO_HMAC
|
select CRYPTO_HMAC
|
||||||
select CRYPTO_SHA256
|
select CRYPTO_SHA256
|
||||||
|
|
||||||
|
config CRYPTO_DF80090A
|
||||||
|
tristate
|
||||||
|
select CRYPTO_AES
|
||||||
|
select CRYPTO_CTR
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
menu "Userspace interface"
|
menu "Userspace interface"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,4 +209,6 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
|
||||||
#
|
#
|
||||||
obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
|
obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_CRYPTO_DF80090A) += df_sp80090a.o
|
||||||
|
|
||||||
obj-$(CONFIG_CRYPTO_KRB5) += krb5/
|
obj-$(CONFIG_CRYPTO_KRB5) += krb5/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
// 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/df_sp80090a.h>
|
||||||
|
#include <crypto/internal/drbg.h>
|
||||||
|
|
||||||
|
static void drbg_kcapi_symsetkey(struct crypto_cipher *tfm,
|
||||||
|
const unsigned char *key,
|
||||||
|
u8 keylen);
|
||||||
|
static int drbg_kcapi_sym(struct crypto_cipher *tfm, unsigned char *outval,
|
||||||
|
const struct drbg_string *in, u8 blocklen_bytes);
|
||||||
|
|
||||||
|
static void drbg_kcapi_symsetkey(struct crypto_cipher *tfm,
|
||||||
|
const unsigned char *key, u8 keylen)
|
||||||
|
{
|
||||||
|
crypto_cipher_setkey(tfm, key, keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drbg_kcapi_sym(struct crypto_cipher *tfm, unsigned char *outval,
|
||||||
|
const struct drbg_string *in, u8 blocklen_bytes)
|
||||||
|
{
|
||||||
|
/* there is only component in *in */
|
||||||
|
BUG_ON(in->len < blocklen_bytes);
|
||||||
|
crypto_cipher_encrypt_one(tfm, outval, in->buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BCC function for CTR DRBG as defined in 10.4.3 */
|
||||||
|
|
||||||
|
static int drbg_ctr_bcc(struct crypto_cipher *tfm,
|
||||||
|
unsigned char *out, const unsigned char *key,
|
||||||
|
struct list_head *in,
|
||||||
|
u8 blocklen_bytes,
|
||||||
|
u8 keylen)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
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(tfm, 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;
|
||||||
|
ret = drbg_kcapi_sym(tfm, out, &data, blocklen_bytes);
|
||||||
|
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(tfm, out, &data, blocklen_bytes);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_cipher *tfm,
|
||||||
|
unsigned char *df_data, size_t bytes_to_return,
|
||||||
|
struct list_head *seedlist,
|
||||||
|
u8 blocklen_bytes,
|
||||||
|
u8 statelen)
|
||||||
|
{
|
||||||
|
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 + 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 */
|
||||||
|
ret = drbg_ctr_bcc(tfm, temp + templen, K, &bcc_list,
|
||||||
|
blocklen_bytes, keylen);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
/* 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(tfm, 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
|
||||||
|
*/
|
||||||
|
ret = drbg_kcapi_sym(tfm, X, &cipherin, blocklen_bytes);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
memset(iv, 0, blocklen_bytes);
|
||||||
|
memset(temp, 0, statelen + blocklen_bytes);
|
||||||
|
memset(pad, 0, blocklen_bytes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
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");
|
||||||
244
crypto/drbg.c
244
crypto/drbg.c
|
|
@ -98,6 +98,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <crypto/drbg.h>
|
#include <crypto/drbg.h>
|
||||||
|
#include <crypto/df_sp80090a.h>
|
||||||
#include <crypto/internal/cipher.h>
|
#include <crypto/internal/cipher.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
|
@ -261,26 +262,6 @@ static int drbg_fips_continuous_test(struct drbg_state *drbg,
|
||||||
return 0;
|
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
|
* 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_pr_ctr_aes128");
|
||||||
MODULE_ALIAS_CRYPTO("drbg_nopr_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_init_sym_kernel(struct drbg_state *drbg);
|
||||||
static int drbg_fini_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,
|
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);
|
u8 *outbuf, u32 outlen);
|
||||||
#define DRBG_OUTSCRATCHLEN 256
|
#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,
|
static int drbg_ctr_df(struct drbg_state *drbg,
|
||||||
unsigned char *df_data, size_t bytes_to_return,
|
unsigned char *df_data, size_t bytes_to_return,
|
||||||
struct list_head *seedlist)
|
struct list_head *seedlist)
|
||||||
{
|
{
|
||||||
int ret = -EFAULT;
|
return crypto_drbg_ctr_df(drbg->priv_data, df_data, drbg_statelen(drbg),
|
||||||
unsigned char L_N[8];
|
seedlist, drbg_blocklen(drbg), drbg_statelen(drbg));
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1310,10 +1097,8 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
|
||||||
sb_size = 0;
|
sb_size = 0;
|
||||||
else if (drbg->core->flags & DRBG_CTR)
|
else if (drbg->core->flags & DRBG_CTR)
|
||||||
sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */
|
sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */
|
||||||
drbg_statelen(drbg) + /* df_data */
|
crypto_drbg_ctr_df_datalen(drbg_statelen(drbg),
|
||||||
drbg_blocklen(drbg) + /* pad */
|
drbg_blocklen(drbg));
|
||||||
drbg_blocklen(drbg) + /* iv */
|
|
||||||
drbg_statelen(drbg) + drbg_blocklen(drbg); /* temp */
|
|
||||||
else
|
else
|
||||||
sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg);
|
sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg);
|
||||||
|
|
||||||
|
|
@ -1800,25 +1585,6 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
|
||||||
return alignmask;
|
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,
|
static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
|
||||||
u8 *inbuf, u32 inlen,
|
u8 *inbuf, u32 inlen,
|
||||||
u8 *outbuf, u32 outlen)
|
u8 *outbuf, u32 outlen)
|
||||||
|
|
|
||||||
|
|
@ -728,6 +728,7 @@ config CRYPTO_DEV_TEGRA
|
||||||
config CRYPTO_DEV_XILINX_TRNG
|
config CRYPTO_DEV_XILINX_TRNG
|
||||||
tristate "Support for Xilinx True Random Generator"
|
tristate "Support for Xilinx True Random Generator"
|
||||||
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
|
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
|
||||||
|
select CRYPTO_DF80090A
|
||||||
select CRYPTO_RNG
|
select CRYPTO_RNG
|
||||||
select HW_RANDOM
|
select HW_RANDOM
|
||||||
help
|
help
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright Stephan Mueller <smueller@chronox.de>, 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CRYPTO_DF80090A_H
|
||||||
|
#define _CRYPTO_DF80090A_H
|
||||||
|
|
||||||
|
#include <crypto/internal/cipher.h>
|
||||||
|
|
||||||
|
static inline int crypto_drbg_ctr_df_datalen(u8 statelen, u8 blocklen)
|
||||||
|
{
|
||||||
|
return statelen + /* df_data */
|
||||||
|
blocklen + /* pad */
|
||||||
|
blocklen + /* iv */
|
||||||
|
statelen + blocklen; /* temp */
|
||||||
|
}
|
||||||
|
|
||||||
|
int crypto_drbg_ctr_df(struct crypto_cipher *tfm,
|
||||||
|
unsigned char *df_data,
|
||||||
|
size_t bytes_to_return,
|
||||||
|
struct list_head *seedlist,
|
||||||
|
u8 blocklen_bytes,
|
||||||
|
u8 statelen);
|
||||||
|
|
||||||
|
#endif /* _CRYPTO_DF80090A_H */
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <crypto/internal/drbg.h>
|
||||||
#include <crypto/internal/rng.h>
|
#include <crypto/internal/rng.h>
|
||||||
#include <crypto/rng.h>
|
#include <crypto/rng.h>
|
||||||
#include <linux/fips.h>
|
#include <linux/fips.h>
|
||||||
|
|
@ -54,30 +55,6 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct drbg_state;
|
struct drbg_state;
|
||||||
typedef uint32_t drbg_flag_t;
|
typedef uint32_t drbg_flag_t;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NIST SP800-90A DRBG derivation function
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
* 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
|
||||||
Loading…
Reference in New Issue