crypto: drbg - use of kernel linked list
The DRBG-style linked list to manage input data that is fed into the cipher invocations is replaced with the kernel linked list implementation. The change is transparent to users of the interfaces offered by the DRBG. Therefore, no changes to the testmgr code is needed. Reported-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Stephan Mueller <smueller@chronox.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
8fecaad77f
commit
8c98716601
233
crypto/drbg.c
233
crypto/drbg.c
|
@ -370,13 +370,12 @@ static int drbg_fini_sym_kernel(struct drbg_state *drbg);
|
||||||
/* BCC function for CTR DRBG as defined in 10.4.3 */
|
/* BCC function for CTR DRBG as defined in 10.4.3 */
|
||||||
static int drbg_ctr_bcc(struct drbg_state *drbg,
|
static int drbg_ctr_bcc(struct drbg_state *drbg,
|
||||||
unsigned char *out, const unsigned char *key,
|
unsigned char *out, const unsigned char *key,
|
||||||
struct drbg_string *in)
|
struct list_head *in)
|
||||||
{
|
{
|
||||||
int ret = -EFAULT;
|
int ret = 0;
|
||||||
struct drbg_string *curr = in;
|
struct drbg_string *curr = NULL;
|
||||||
size_t inpos = curr->len;
|
|
||||||
const unsigned char *pos = curr->buf;
|
|
||||||
struct drbg_string data;
|
struct drbg_string data;
|
||||||
|
short cnt = 0;
|
||||||
|
|
||||||
drbg_string_fill(&data, out, drbg_blocklen(drbg));
|
drbg_string_fill(&data, out, drbg_blocklen(drbg));
|
||||||
|
|
||||||
|
@ -384,39 +383,29 @@ static int drbg_ctr_bcc(struct drbg_state *drbg,
|
||||||
memset(out, 0, drbg_blocklen(drbg));
|
memset(out, 0, drbg_blocklen(drbg));
|
||||||
|
|
||||||
/* 10.4.3 step 2 / 4 */
|
/* 10.4.3 step 2 / 4 */
|
||||||
while (inpos) {
|
list_for_each_entry(curr, in, list) {
|
||||||
short cnt = 0;
|
const unsigned char *pos = curr->buf;
|
||||||
|
size_t len = curr->len;
|
||||||
/* 10.4.3 step 4.1 */
|
/* 10.4.3 step 4.1 */
|
||||||
for (cnt = 0; cnt < drbg_blocklen(drbg); cnt++) {
|
while (len) {
|
||||||
out[cnt] ^= *pos;
|
/* 10.4.3 step 4.2 */
|
||||||
pos++; inpos--;
|
if (drbg_blocklen(drbg) == cnt) {
|
||||||
/*
|
cnt = 0;
|
||||||
* The following branch implements the linked list
|
ret = drbg_kcapi_sym(drbg, key, out, &data);
|
||||||
* iteration of drbg_string *in. If we are at the
|
if (ret)
|
||||||
* end of the current list member, we have to start
|
return ret;
|
||||||
* using the next member if available. The inpos
|
|
||||||
* value always points to the current byte and will
|
|
||||||
* be zero if we have processed the last byte of
|
|
||||||
* the last linked list member.
|
|
||||||
*/
|
|
||||||
if (0 == inpos) {
|
|
||||||
curr = curr->next;
|
|
||||||
if (NULL != curr) {
|
|
||||||
pos = curr->buf;
|
|
||||||
inpos = curr->len;
|
|
||||||
} else {
|
|
||||||
inpos = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
out[cnt] ^= *pos;
|
||||||
|
pos++;
|
||||||
|
cnt++;
|
||||||
|
len--;
|
||||||
}
|
}
|
||||||
/* 10.4.3 step 4.2 */
|
|
||||||
ret = drbg_kcapi_sym(drbg, key, out, &data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
/* 10.4.3 step 2 */
|
|
||||||
}
|
}
|
||||||
return 0;
|
/* 10.4.3 step 4.2 for last block */
|
||||||
|
if (cnt)
|
||||||
|
ret = drbg_kcapi_sym(drbg, key, out, &data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -461,13 +450,13 @@ static int drbg_ctr_bcc(struct drbg_state *drbg,
|
||||||
/* Derivation Function for CTR DRBG as defined in 10.4.2 */
|
/* 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 drbg_string *addtl)
|
struct list_head *seedlist)
|
||||||
{
|
{
|
||||||
int ret = -EFAULT;
|
int ret = -EFAULT;
|
||||||
unsigned char L_N[8];
|
unsigned char L_N[8];
|
||||||
/* S3 is input */
|
/* S3 is input */
|
||||||
struct drbg_string S1, S2, S4, cipherin;
|
struct drbg_string S1, S2, S4, cipherin;
|
||||||
struct drbg_string *tempstr = addtl;
|
LIST_HEAD(bcc_list);
|
||||||
unsigned char *pad = df_data + drbg_statelen(drbg);
|
unsigned char *pad = df_data + drbg_statelen(drbg);
|
||||||
unsigned char *iv = pad + drbg_blocklen(drbg);
|
unsigned char *iv = pad + drbg_blocklen(drbg);
|
||||||
unsigned char *temp = iv + drbg_blocklen(drbg);
|
unsigned char *temp = iv + drbg_blocklen(drbg);
|
||||||
|
@ -484,6 +473,7 @@ static int drbg_ctr_df(struct drbg_state *drbg,
|
||||||
unsigned char *X;
|
unsigned char *X;
|
||||||
size_t generated_len = 0;
|
size_t generated_len = 0;
|
||||||
size_t inputlen = 0;
|
size_t inputlen = 0;
|
||||||
|
struct drbg_string *seed = NULL;
|
||||||
|
|
||||||
memset(pad, 0, drbg_blocklen(drbg));
|
memset(pad, 0, drbg_blocklen(drbg));
|
||||||
memset(iv, 0, drbg_blocklen(drbg));
|
memset(iv, 0, drbg_blocklen(drbg));
|
||||||
|
@ -496,8 +486,8 @@ static int drbg_ctr_df(struct drbg_state *drbg,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* 10.4.2 step 2 -- calculate the entire length of all input data */
|
/* 10.4.2 step 2 -- calculate the entire length of all input data */
|
||||||
for (; NULL != tempstr; tempstr = tempstr->next)
|
list_for_each_entry(seed, seedlist, list)
|
||||||
inputlen += tempstr->len;
|
inputlen += seed->len;
|
||||||
drbg_int2byte(&L_N[0], inputlen, 4);
|
drbg_int2byte(&L_N[0], inputlen, 4);
|
||||||
|
|
||||||
/* 10.4.2 step 3 */
|
/* 10.4.2 step 3 */
|
||||||
|
@ -518,20 +508,12 @@ static int drbg_ctr_df(struct drbg_state *drbg,
|
||||||
|
|
||||||
/* 10.4.2 step 4 -- first fill the linked list and then order it */
|
/* 10.4.2 step 4 -- first fill the linked list and then order it */
|
||||||
drbg_string_fill(&S1, iv, drbg_blocklen(drbg));
|
drbg_string_fill(&S1, iv, drbg_blocklen(drbg));
|
||||||
|
list_add_tail(&S1.list, &bcc_list);
|
||||||
drbg_string_fill(&S2, L_N, sizeof(L_N));
|
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);
|
drbg_string_fill(&S4, pad, padlen);
|
||||||
S1.next = &S2;
|
list_add_tail(&S4.list, &bcc_list);
|
||||||
S2.next = addtl;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Splice in addtl between S2 and S4 -- we place S4 at the end
|
|
||||||
* of the input data chain. As this code is only triggered when
|
|
||||||
* addtl is not NULL, no NULL checks are necessary.
|
|
||||||
*/
|
|
||||||
tempstr = addtl;
|
|
||||||
while (tempstr->next)
|
|
||||||
tempstr = tempstr->next;
|
|
||||||
tempstr->next = &S4;
|
|
||||||
|
|
||||||
/* 10.4.2 step 9 */
|
/* 10.4.2 step 9 */
|
||||||
while (templen < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) {
|
while (templen < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) {
|
||||||
|
@ -542,7 +524,7 @@ static int drbg_ctr_df(struct drbg_state *drbg,
|
||||||
*/
|
*/
|
||||||
drbg_int2byte(iv, i, 4);
|
drbg_int2byte(iv, i, 4);
|
||||||
/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
|
/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
|
||||||
ret = drbg_ctr_bcc(drbg, temp + templen, K, &S1);
|
ret = drbg_ctr_bcc(drbg, temp + templen, K, &bcc_list);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
/* 10.4.2 step 9.3 */
|
/* 10.4.2 step 9.3 */
|
||||||
|
@ -586,8 +568,8 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update function of CTR DRBG as defined in 10.2.1.2 */
|
/* update function of CTR DRBG as defined in 10.2.1.2 */
|
||||||
static int drbg_ctr_update(struct drbg_state *drbg,
|
static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed,
|
||||||
struct drbg_string *addtl, int reseed)
|
int reseed)
|
||||||
{
|
{
|
||||||
int ret = -EFAULT;
|
int ret = -EFAULT;
|
||||||
/* 10.2.1.2 step 1 */
|
/* 10.2.1.2 step 1 */
|
||||||
|
@ -603,9 +585,8 @@ static int drbg_ctr_update(struct drbg_state *drbg,
|
||||||
memset(df_data, 0, drbg_statelen(drbg));
|
memset(df_data, 0, drbg_statelen(drbg));
|
||||||
|
|
||||||
/* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */
|
/* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */
|
||||||
if (addtl && 0 < addtl->len) {
|
if (seed) {
|
||||||
ret = drbg_ctr_df(drbg, df_data, drbg_statelen(drbg),
|
ret = drbg_ctr_df(drbg, df_data, drbg_statelen(drbg), seed);
|
||||||
addtl);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -665,8 +646,10 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
|
||||||
|
|
||||||
/* 10.2.1.5.2 step 2 */
|
/* 10.2.1.5.2 step 2 */
|
||||||
if (addtl && 0 < addtl->len) {
|
if (addtl && 0 < addtl->len) {
|
||||||
addtl->next = NULL;
|
LIST_HEAD(addtllist);
|
||||||
ret = drbg_ctr_update(drbg, addtl, 1);
|
|
||||||
|
list_add_tail(&addtl->list, &addtllist);
|
||||||
|
ret = drbg_ctr_update(drbg, &addtllist, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -697,16 +680,21 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
|
||||||
drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
|
drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 10.2.1.5.2 step 6 */
|
|
||||||
if (addtl)
|
|
||||||
addtl->next = NULL;
|
|
||||||
/*
|
/*
|
||||||
|
* 10.2.1.5.2 step 6
|
||||||
* The following call invokes the DF function again which could be
|
* The following call invokes the DF function again which could be
|
||||||
* optimized. In step 2, the "additional_input" after step 2 is the
|
* optimized. In step 2, the "additional_input" after step 2 is the
|
||||||
* output of the DF function. If this result would be saved, the DF
|
* output of the DF function. If this result would be saved, the DF
|
||||||
* function would not need to be invoked again at this point.
|
* function would not need to be invoked again at this point.
|
||||||
*/
|
*/
|
||||||
ret = drbg_ctr_update(drbg, addtl, 1);
|
if (addtl && 0 < addtl->len) {
|
||||||
|
LIST_HEAD(addtllist);
|
||||||
|
|
||||||
|
list_add_tail(&addtl->list, &addtllist);
|
||||||
|
ret = drbg_ctr_update(drbg, &addtllist, 1);
|
||||||
|
} else {
|
||||||
|
ret = drbg_ctr_update(drbg, NULL, 1);
|
||||||
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
len = ret;
|
len = ret;
|
||||||
|
|
||||||
|
@ -729,19 +717,21 @@ static struct drbg_state_ops drbg_ctr_ops = {
|
||||||
|
|
||||||
#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC)
|
#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC)
|
||||||
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
|
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
|
||||||
unsigned char *outval, const struct drbg_string *in);
|
unsigned char *outval, const struct list_head *in);
|
||||||
static int drbg_init_hash_kernel(struct drbg_state *drbg);
|
static int drbg_init_hash_kernel(struct drbg_state *drbg);
|
||||||
static int drbg_fini_hash_kernel(struct drbg_state *drbg);
|
static int drbg_fini_hash_kernel(struct drbg_state *drbg);
|
||||||
#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
|
#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
|
||||||
|
|
||||||
#ifdef CONFIG_CRYPTO_DRBG_HMAC
|
#ifdef CONFIG_CRYPTO_DRBG_HMAC
|
||||||
/* update function of HMAC DRBG as defined in 10.1.2.2 */
|
/* update function of HMAC DRBG as defined in 10.1.2.2 */
|
||||||
static int drbg_hmac_update(struct drbg_state *drbg,
|
static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
|
||||||
struct drbg_string *seed, int reseed)
|
int reseed)
|
||||||
{
|
{
|
||||||
int ret = -EFAULT;
|
int ret = -EFAULT;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct drbg_string seed1, seed2, cipherin;
|
struct drbg_string seed1, seed2, vdata;
|
||||||
|
LIST_HEAD(seedlist);
|
||||||
|
LIST_HEAD(vdatalist);
|
||||||
|
|
||||||
if (!reseed) {
|
if (!reseed) {
|
||||||
/* 10.1.2.3 step 2 */
|
/* 10.1.2.3 step 2 */
|
||||||
|
@ -750,13 +740,16 @@ static int drbg_hmac_update(struct drbg_state *drbg,
|
||||||
}
|
}
|
||||||
|
|
||||||
drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg));
|
||||||
|
list_add_tail(&seed1.list, &seedlist);
|
||||||
/* buffer of seed2 will be filled in for loop below with one byte */
|
/* buffer of seed2 will be filled in for loop below with one byte */
|
||||||
drbg_string_fill(&seed2, NULL, 1);
|
drbg_string_fill(&seed2, NULL, 1);
|
||||||
seed1.next = &seed2;
|
list_add_tail(&seed2.list, &seedlist);
|
||||||
/* input data of seed is allowed to be NULL at this point */
|
/* input data of seed is allowed to be NULL at this point */
|
||||||
seed2.next = seed;
|
if (seed)
|
||||||
|
list_splice_tail(seed, &seedlist);
|
||||||
|
|
||||||
drbg_string_fill(&cipherin, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&vdata, drbg->V, drbg_statelen(drbg));
|
||||||
|
list_add_tail(&vdata.list, &vdatalist);
|
||||||
for (i = 2; 0 < i; i--) {
|
for (i = 2; 0 < i; i--) {
|
||||||
/* first round uses 0x0, second 0x1 */
|
/* first round uses 0x0, second 0x1 */
|
||||||
unsigned char prefix = DRBG_PREFIX0;
|
unsigned char prefix = DRBG_PREFIX0;
|
||||||
|
@ -764,17 +757,17 @@ static int drbg_hmac_update(struct drbg_state *drbg,
|
||||||
prefix = DRBG_PREFIX1;
|
prefix = DRBG_PREFIX1;
|
||||||
/* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */
|
/* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */
|
||||||
seed2.buf = &prefix;
|
seed2.buf = &prefix;
|
||||||
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->C, &seed1);
|
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->C, &seedlist);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* 10.1.2.2 step 2 and 5 -- HMAC for V */
|
/* 10.1.2.2 step 2 and 5 -- HMAC for V */
|
||||||
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &cipherin);
|
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &vdatalist);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* 10.1.2.2 step 3 */
|
/* 10.1.2.2 step 3 */
|
||||||
if (!seed || 0 == seed->len)
|
if (!seed)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,20 +783,24 @@ static int drbg_hmac_generate(struct drbg_state *drbg,
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct drbg_string data;
|
struct drbg_string data;
|
||||||
|
LIST_HEAD(datalist);
|
||||||
|
|
||||||
/* 10.1.2.5 step 2 */
|
/* 10.1.2.5 step 2 */
|
||||||
if (addtl && 0 < addtl->len) {
|
if (addtl && 0 < addtl->len) {
|
||||||
addtl->next = NULL;
|
LIST_HEAD(addtllist);
|
||||||
ret = drbg_hmac_update(drbg, addtl, 1);
|
|
||||||
|
list_add_tail(&addtl->list, &addtllist);
|
||||||
|
ret = drbg_hmac_update(drbg, &addtllist, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
drbg_string_fill(&data, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&data, drbg->V, drbg_statelen(drbg));
|
||||||
|
list_add_tail(&data.list, &datalist);
|
||||||
while (len < buflen) {
|
while (len < buflen) {
|
||||||
unsigned int outlen = 0;
|
unsigned int outlen = 0;
|
||||||
/* 10.1.2.5 step 4.1 */
|
/* 10.1.2.5 step 4.1 */
|
||||||
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &data);
|
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &datalist);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
|
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
|
||||||
|
@ -817,9 +814,14 @@ static int drbg_hmac_generate(struct drbg_state *drbg,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 10.1.2.5 step 6 */
|
/* 10.1.2.5 step 6 */
|
||||||
if (addtl)
|
if (addtl && 0 < addtl->len) {
|
||||||
addtl->next = NULL;
|
LIST_HEAD(addtllist);
|
||||||
ret = drbg_hmac_update(drbg, addtl, 1);
|
|
||||||
|
list_add_tail(&addtl->list, &addtllist);
|
||||||
|
ret = drbg_hmac_update(drbg, &addtllist, 1);
|
||||||
|
} else {
|
||||||
|
ret = drbg_hmac_update(drbg, NULL, 1);
|
||||||
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -858,13 +860,13 @@ static struct drbg_state_ops drbg_hmac_ops = {
|
||||||
/* Derivation Function for Hash DRBG as defined in 10.4.1 */
|
/* Derivation Function for Hash DRBG as defined in 10.4.1 */
|
||||||
static int drbg_hash_df(struct drbg_state *drbg,
|
static int drbg_hash_df(struct drbg_state *drbg,
|
||||||
unsigned char *outval, size_t outlen,
|
unsigned char *outval, size_t outlen,
|
||||||
struct drbg_string *entropy)
|
struct list_head *entropylist)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
unsigned char input[5];
|
unsigned char input[5];
|
||||||
unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg);
|
unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg);
|
||||||
struct drbg_string data1;
|
struct drbg_string data;
|
||||||
|
|
||||||
memset(tmp, 0, drbg_blocklen(drbg));
|
memset(tmp, 0, drbg_blocklen(drbg));
|
||||||
|
|
||||||
|
@ -873,14 +875,14 @@ static int drbg_hash_df(struct drbg_state *drbg,
|
||||||
drbg_int2byte(&input[1], (outlen * 8), 4);
|
drbg_int2byte(&input[1], (outlen * 8), 4);
|
||||||
|
|
||||||
/* 10.4.1 step 4.1 -- concatenation of data for input into hash */
|
/* 10.4.1 step 4.1 -- concatenation of data for input into hash */
|
||||||
drbg_string_fill(&data1, input, 5);
|
drbg_string_fill(&data, input, 5);
|
||||||
data1.next = entropy;
|
list_add(&data.list, entropylist);
|
||||||
|
|
||||||
/* 10.4.1 step 4 */
|
/* 10.4.1 step 4 */
|
||||||
while (len < outlen) {
|
while (len < outlen) {
|
||||||
short blocklen = 0;
|
short blocklen = 0;
|
||||||
/* 10.4.1 step 4.1 */
|
/* 10.4.1 step 4.1 */
|
||||||
ret = drbg_kcapi_hash(drbg, NULL, tmp, &data1);
|
ret = drbg_kcapi_hash(drbg, NULL, tmp, entropylist);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
/* 10.4.1 step 4.2 */
|
/* 10.4.1 step 4.2 */
|
||||||
|
@ -897,11 +899,13 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */
|
/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */
|
||||||
static int drbg_hash_update(struct drbg_state *drbg, struct drbg_string *seed,
|
static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed,
|
||||||
int reseed)
|
int reseed)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct drbg_string data1, data2;
|
struct drbg_string data1, data2;
|
||||||
|
LIST_HEAD(datalist);
|
||||||
|
LIST_HEAD(datalist2);
|
||||||
unsigned char *V = drbg->scratchpad;
|
unsigned char *V = drbg->scratchpad;
|
||||||
unsigned char prefix = DRBG_PREFIX1;
|
unsigned char prefix = DRBG_PREFIX1;
|
||||||
|
|
||||||
|
@ -913,26 +917,25 @@ static int drbg_hash_update(struct drbg_state *drbg, struct drbg_string *seed,
|
||||||
/* 10.1.1.3 step 1 */
|
/* 10.1.1.3 step 1 */
|
||||||
memcpy(V, drbg->V, drbg_statelen(drbg));
|
memcpy(V, drbg->V, drbg_statelen(drbg));
|
||||||
drbg_string_fill(&data1, &prefix, 1);
|
drbg_string_fill(&data1, &prefix, 1);
|
||||||
|
list_add_tail(&data1.list, &datalist);
|
||||||
drbg_string_fill(&data2, V, drbg_statelen(drbg));
|
drbg_string_fill(&data2, V, drbg_statelen(drbg));
|
||||||
data1.next = &data2;
|
list_add_tail(&data2.list, &datalist);
|
||||||
data2.next = seed;
|
|
||||||
} else {
|
|
||||||
drbg_string_fill(&data1, seed->buf, seed->len);
|
|
||||||
data1.next = seed->next;
|
|
||||||
}
|
}
|
||||||
|
list_splice_tail(seed, &datalist);
|
||||||
|
|
||||||
/* 10.1.1.2 / 10.1.1.3 step 2 and 3 */
|
/* 10.1.1.2 / 10.1.1.3 step 2 and 3 */
|
||||||
ret = drbg_hash_df(drbg, drbg->V, drbg_statelen(drbg), &data1);
|
ret = drbg_hash_df(drbg, drbg->V, drbg_statelen(drbg), &datalist);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* 10.1.1.2 / 10.1.1.3 step 4 */
|
/* 10.1.1.2 / 10.1.1.3 step 4 */
|
||||||
prefix = DRBG_PREFIX0;
|
prefix = DRBG_PREFIX0;
|
||||||
drbg_string_fill(&data1, &prefix, 1);
|
drbg_string_fill(&data1, &prefix, 1);
|
||||||
|
list_add_tail(&data1.list, &datalist2);
|
||||||
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
||||||
data1.next = &data2;
|
list_add_tail(&data2.list, &datalist2);
|
||||||
/* 10.1.1.2 / 10.1.1.3 step 4 */
|
/* 10.1.1.2 / 10.1.1.3 step 4 */
|
||||||
ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &data1);
|
ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
memset(drbg->scratchpad, 0, drbg_statelen(drbg));
|
memset(drbg->scratchpad, 0, drbg_statelen(drbg));
|
||||||
|
@ -945,7 +948,7 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg,
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct drbg_string data1, data2;
|
struct drbg_string data1, data2;
|
||||||
struct drbg_string *data3;
|
LIST_HEAD(datalist);
|
||||||
unsigned char prefix = DRBG_PREFIX2;
|
unsigned char prefix = DRBG_PREFIX2;
|
||||||
|
|
||||||
/* this is value w as per documentation */
|
/* this is value w as per documentation */
|
||||||
|
@ -958,11 +961,10 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg,
|
||||||
/* 10.1.1.4 step 2a */
|
/* 10.1.1.4 step 2a */
|
||||||
drbg_string_fill(&data1, &prefix, 1);
|
drbg_string_fill(&data1, &prefix, 1);
|
||||||
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
||||||
data3 = addtl;
|
list_add_tail(&data1.list, &datalist);
|
||||||
data1.next = &data2;
|
list_add_tail(&data2.list, &datalist);
|
||||||
data2.next = data3;
|
list_add_tail(&addtl->list, &datalist);
|
||||||
data3->next = NULL;
|
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
|
||||||
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &data1);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -985,6 +987,7 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
|
||||||
unsigned char *src = drbg->scratchpad;
|
unsigned char *src = drbg->scratchpad;
|
||||||
unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg);
|
unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg);
|
||||||
struct drbg_string data;
|
struct drbg_string data;
|
||||||
|
LIST_HEAD(datalist);
|
||||||
unsigned char prefix = DRBG_PREFIX1;
|
unsigned char prefix = DRBG_PREFIX1;
|
||||||
|
|
||||||
memset(src, 0, drbg_statelen(drbg));
|
memset(src, 0, drbg_statelen(drbg));
|
||||||
|
@ -994,10 +997,11 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
|
||||||
memcpy(src, drbg->V, drbg_statelen(drbg));
|
memcpy(src, drbg->V, drbg_statelen(drbg));
|
||||||
|
|
||||||
drbg_string_fill(&data, src, drbg_statelen(drbg));
|
drbg_string_fill(&data, src, drbg_statelen(drbg));
|
||||||
|
list_add_tail(&data.list, &datalist);
|
||||||
while (len < buflen) {
|
while (len < buflen) {
|
||||||
unsigned int outlen = 0;
|
unsigned int outlen = 0;
|
||||||
/* 10.1.1.4 step hashgen 4.1 */
|
/* 10.1.1.4 step hashgen 4.1 */
|
||||||
ret = drbg_kcapi_hash(drbg, NULL, dst, &data);
|
ret = drbg_kcapi_hash(drbg, NULL, dst, &datalist);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
len = ret;
|
len = ret;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1032,6 +1036,7 @@ static int drbg_hash_generate(struct drbg_state *drbg,
|
||||||
unsigned char req[8];
|
unsigned char req[8];
|
||||||
unsigned char prefix = DRBG_PREFIX3;
|
unsigned char prefix = DRBG_PREFIX3;
|
||||||
struct drbg_string data1, data2;
|
struct drbg_string data1, data2;
|
||||||
|
LIST_HEAD(datalist);
|
||||||
|
|
||||||
/* 10.1.1.4 step 2 */
|
/* 10.1.1.4 step 2 */
|
||||||
ret = drbg_hash_process_addtl(drbg, addtl);
|
ret = drbg_hash_process_addtl(drbg, addtl);
|
||||||
|
@ -1044,9 +1049,10 @@ static int drbg_hash_generate(struct drbg_state *drbg,
|
||||||
memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
|
memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
|
||||||
/* 10.1.1.4 step 4 */
|
/* 10.1.1.4 step 4 */
|
||||||
drbg_string_fill(&data1, &prefix, 1);
|
drbg_string_fill(&data1, &prefix, 1);
|
||||||
|
list_add_tail(&data1.list, &datalist);
|
||||||
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
|
||||||
data1.next = &data2;
|
list_add_tail(&data2.list, &datalist);
|
||||||
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &data1);
|
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
len = ret;
|
len = ret;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1099,6 +1105,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
|
||||||
unsigned char *entropy = NULL;
|
unsigned char *entropy = NULL;
|
||||||
size_t entropylen = 0;
|
size_t entropylen = 0;
|
||||||
struct drbg_string data1;
|
struct drbg_string data1;
|
||||||
|
LIST_HEAD(seedlist);
|
||||||
|
|
||||||
/* 9.1 / 9.2 / 9.3.1 step 3 */
|
/* 9.1 / 9.2 / 9.3.1 step 3 */
|
||||||
if (pers && pers->len > (drbg_max_addtl(drbg))) {
|
if (pers && pers->len > (drbg_max_addtl(drbg))) {
|
||||||
|
@ -1133,18 +1140,19 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
|
||||||
get_random_bytes(entropy, entropylen);
|
get_random_bytes(entropy, entropylen);
|
||||||
drbg_string_fill(&data1, entropy, entropylen);
|
drbg_string_fill(&data1, entropy, entropylen);
|
||||||
}
|
}
|
||||||
|
list_add_tail(&data1.list, &seedlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* concatenation of entropy with personalization str / addtl input)
|
* concatenation of entropy with personalization str / addtl input)
|
||||||
* the variable pers is directly handed in by the caller, so check its
|
* the variable pers is directly handed in by the caller, so check its
|
||||||
* contents whether it is appropriate
|
* contents whether it is appropriate
|
||||||
*/
|
*/
|
||||||
if (pers && pers->buf && 0 < pers->len && NULL == pers->next) {
|
if (pers && pers->buf && 0 < pers->len) {
|
||||||
data1.next = pers;
|
list_add_tail(&pers->list, &seedlist);
|
||||||
pr_devel("DRBG: using personalization string\n");
|
pr_devel("DRBG: using personalization string\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = drbg->d_ops->update(drbg, &data1, reseed);
|
ret = drbg->d_ops->update(drbg, &seedlist, reseed);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1642,15 +1650,16 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
|
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
|
||||||
unsigned char *outval, const struct drbg_string *in)
|
unsigned char *outval, const struct list_head *in)
|
||||||
{
|
{
|
||||||
struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
|
struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
|
||||||
|
struct drbg_string *input = NULL;
|
||||||
|
|
||||||
if (key)
|
if (key)
|
||||||
crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
|
crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
|
||||||
crypto_shash_init(&sdesc->shash);
|
crypto_shash_init(&sdesc->shash);
|
||||||
for (; NULL != in; in = in->next)
|
list_for_each_entry(input, in, list)
|
||||||
crypto_shash_update(&sdesc->shash, in->buf, in->len);
|
crypto_shash_update(&sdesc->shash, input->buf, input->len);
|
||||||
return crypto_shash_final(&sdesc->shash, outval);
|
return crypto_shash_final(&sdesc->shash, outval);
|
||||||
}
|
}
|
||||||
#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
|
#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
|
||||||
|
@ -1785,12 +1794,15 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, u8 *rdata,
|
||||||
return drbg_generate_long(drbg, rdata, dlen, NULL);
|
return drbg_generate_long(drbg, rdata, dlen, NULL);
|
||||||
} else {
|
} else {
|
||||||
struct drbg_gen *data = (struct drbg_gen *)rdata;
|
struct drbg_gen *data = (struct drbg_gen *)rdata;
|
||||||
|
struct drbg_string addtl;
|
||||||
/* catch NULL pointer */
|
/* catch NULL pointer */
|
||||||
if (!data)
|
if (!data)
|
||||||
return 0;
|
return 0;
|
||||||
drbg_set_testdata(drbg, data->test_data);
|
drbg_set_testdata(drbg, data->test_data);
|
||||||
|
/* linked list variable is now local to allow modification */
|
||||||
|
drbg_string_fill(&addtl, data->addtl->buf, data->addtl->len);
|
||||||
return drbg_generate_long(drbg, data->outbuf, data->outlen,
|
return drbg_generate_long(drbg, data->outbuf, data->outlen,
|
||||||
data->addtl);
|
&addtl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1820,7 +1832,10 @@ static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
|
||||||
if (!data)
|
if (!data)
|
||||||
return drbg_instantiate(drbg, NULL, coreref, pr);
|
return drbg_instantiate(drbg, NULL, coreref, pr);
|
||||||
drbg_set_testdata(drbg, data->test_data);
|
drbg_set_testdata(drbg, data->test_data);
|
||||||
return drbg_instantiate(drbg, data->addtl, coreref, pr);
|
/* linked list variable is now local to allow modification */
|
||||||
|
drbg_string_fill(&seed_string, data->addtl->buf,
|
||||||
|
data->addtl->len);
|
||||||
|
return drbg_instantiate(drbg, &seed_string, coreref, pr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include <crypto/rng.h>
|
#include <crypto/rng.h>
|
||||||
#include <linux/fips.h>
|
#include <linux/fips.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Concatenation Helper and string operation helper
|
* Concatenation Helper and string operation helper
|
||||||
|
@ -64,7 +65,7 @@
|
||||||
struct drbg_string {
|
struct drbg_string {
|
||||||
const unsigned char *buf;
|
const unsigned char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
struct drbg_string *next;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void drbg_string_fill(struct drbg_string *string,
|
static inline void drbg_string_fill(struct drbg_string *string,
|
||||||
|
@ -72,7 +73,7 @@ static inline void drbg_string_fill(struct drbg_string *string,
|
||||||
{
|
{
|
||||||
string->buf = buf;
|
string->buf = buf;
|
||||||
string->len = len;
|
string->len = len;
|
||||||
string->next = NULL;
|
INIT_LIST_HEAD(&string->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct drbg_state;
|
struct drbg_state;
|
||||||
|
@ -97,7 +98,7 @@ struct drbg_core {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drbg_state_ops {
|
struct drbg_state_ops {
|
||||||
int (*update)(struct drbg_state *drbg, struct drbg_string *seed,
|
int (*update)(struct drbg_state *drbg, struct list_head *seed,
|
||||||
int reseed);
|
int reseed);
|
||||||
int (*generate)(struct drbg_state *drbg,
|
int (*generate)(struct drbg_state *drbg,
|
||||||
unsigned char *buf, unsigned int buflen,
|
unsigned char *buf, unsigned int buflen,
|
||||||
|
|
Loading…
Reference in New Issue