/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */
static int drbg_ctr_generate(struct drbg_state *drbg,
unsigned char *buf, unsigned int buflen,
- struct drbg_string *addtl)
+ struct list_head *addtl)
{
int len = 0;
int ret = 0;
memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
/* 10.2.1.5.2 step 2 */
- if (addtl && 0 < addtl->len) {
- LIST_HEAD(addtllist);
-
- list_add_tail(&addtl->list, &addtllist);
- ret = drbg_ctr_update(drbg, &addtllist, 2);
+ if (addtl && !list_empty(addtl)) {
+ ret = drbg_ctr_update(drbg, addtl, 2);
if (ret)
return 0;
}
static int drbg_hmac_generate(struct drbg_state *drbg,
unsigned char *buf,
unsigned int buflen,
- struct drbg_string *addtl)
+ struct list_head *addtl)
{
int len = 0;
int ret = 0;
LIST_HEAD(datalist);
/* 10.1.2.5 step 2 */
- if (addtl && 0 < addtl->len) {
- LIST_HEAD(addtllist);
-
- list_add_tail(&addtl->list, &addtllist);
- ret = drbg_hmac_update(drbg, &addtllist, 1);
+ if (addtl && !list_empty(addtl)) {
+ ret = drbg_hmac_update(drbg, addtl, 1);
if (ret)
return ret;
}
}
/* 10.1.2.5 step 6 */
- if (addtl && 0 < addtl->len) {
- LIST_HEAD(addtllist);
-
- list_add_tail(&addtl->list, &addtllist);
- ret = drbg_hmac_update(drbg, &addtllist, 1);
- } else {
+ if (addtl && !list_empty(addtl))
+ ret = drbg_hmac_update(drbg, addtl, 1);
+ else
ret = drbg_hmac_update(drbg, NULL, 1);
- }
if (ret)
return ret;
/* processing of additional information string for Hash DRBG */
static int drbg_hash_process_addtl(struct drbg_state *drbg,
- struct drbg_string *addtl)
+ struct list_head *addtl)
{
int ret = 0;
struct drbg_string data1, data2;
memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
/* 10.1.1.4 step 2 */
- if (!addtl || 0 == addtl->len)
+ if (!addtl || list_empty(addtl))
return 0;
/* 10.1.1.4 step 2a */
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
list_add_tail(&data1.list, &datalist);
list_add_tail(&data2.list, &datalist);
- list_add_tail(&addtl->list, &datalist);
+ list_splice_tail(addtl, &datalist);
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
if (ret)
goto out;
/* generate function for Hash DRBG as defined in 10.1.1.4 */
static int drbg_hash_generate(struct drbg_state *drbg,
unsigned char *buf, unsigned int buflen,
- struct drbg_string *addtl)
+ struct list_head *addtl)
{
int len = 0;
int ret = 0;
{
int len = 0;
struct drbg_state *shadow = NULL;
+ LIST_HEAD(addtllist);
+ struct drbg_string timestamp;
+ union {
+ cycles_t cycles;
+ unsigned char char_cycles[sizeof(cycles_t)];
+ } now;
if (0 == buflen || !buf) {
pr_devel("DRBG: no output buffer provided\n");
/* 9.3.1 step 7.4 */
addtl = NULL;
}
+
+ /*
+ * Mix the time stamp into the DRBG state if the DRBG is not in
+ * test mode. If there are two callers invoking the DRBG at the same
+ * time, i.e. before the first caller merges its shadow state back,
+ * both callers would obtain the same random number stream without
+ * changing the state here.
+ */
+ if (!drbg->test_data) {
+ now.cycles = random_get_entropy();
+ drbg_string_fill(×tamp, now.char_cycles, sizeof(cycles_t));
+ list_add_tail(×tamp.list, &addtllist);
+ }
+ if (addtl && 0 < addtl->len)
+ list_add_tail(&addtl->list, &addtllist);
/* 9.3.1 step 8 and 10 */
- len = shadow->d_ops->generate(shadow, buf, buflen, addtl);
+ len = shadow->d_ops->generate(shadow, buf, buflen, &addtllist);
/* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */
shadow->reseed_ctr++;