crypto: drbg - prepare for async seeding
[firefly-linux-kernel-4.4.55.git] / crypto / drbg.c
index 23d444ed3176a8d67babb09b0333794cbb9c777f..36dfece45e88968737d984f5785e81850bf9710f 100644 (file)
@@ -1041,6 +1041,21 @@ static struct drbg_state_ops drbg_hash_ops = {
  * Functions common for DRBG implementations
  ******************************************************************/
 
+static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
+                             int reseed)
+{
+       int ret = drbg->d_ops->update(drbg, seed, reseed);
+
+       if (ret)
+               return ret;
+
+       drbg->seeded = true;
+       /* 10.1.1.2 / 10.1.1.3 step 5 */
+       drbg->reseed_ctr = 1;
+
+       return ret;
+}
+
 /*
  * Seeding or reseeding of the DRBG
  *
@@ -1056,8 +1071,6 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                     bool reseed)
 {
        int ret = 0;
-       unsigned char *entropy = NULL;
-       size_t entropylen = 0;
        struct drbg_string data1;
        LIST_HEAD(seedlist);
 
@@ -1073,26 +1086,10 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                                 drbg->test_data.len);
                pr_devel("DRBG: using test entropy\n");
        } else {
-               /*
-                * Gather entropy equal to the security strength of the DRBG.
-                * With a derivation function, a nonce is required in addition
-                * to the entropy. A nonce must be at least 1/2 of the security
-                * strength of the DRBG in size. Thus, entropy * nonce is 3/2
-                * of the strength. The consideration of a nonce is only
-                * applicable during initial seeding.
-                */
-               entropylen = drbg_sec_strength(drbg->core->flags);
-               if (!entropylen)
-                       return -EFAULT;
-               if (!reseed)
-                       entropylen = ((entropylen + 1) / 2) * 3;
                pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-                        entropylen);
-               entropy = kzalloc(entropylen, GFP_KERNEL);
-               if (!entropy)
-                       return -ENOMEM;
-               get_random_bytes(entropy, entropylen);
-               drbg_string_fill(&data1, entropy, entropylen);
+                        drbg->seed_buf_len);
+               get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+               drbg_string_fill(&data1, drbg->seed_buf, drbg->seed_buf_len);
        }
        list_add_tail(&data1.list, &seedlist);
 
@@ -1111,16 +1108,24 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                memset(drbg->C, 0, drbg_statelen(drbg));
        }
 
-       ret = drbg->d_ops->update(drbg, &seedlist, reseed);
+       ret = __drbg_seed(drbg, &seedlist, reseed);
+
+       /*
+        * Clear the initial entropy buffer as the async call may not overwrite
+        * that buffer for quite some time.
+        */
+       memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
        if (ret)
                goto out;
-
-       drbg->seeded = true;
-       /* 10.1.1.2 / 10.1.1.3 step 5 */
-       drbg->reseed_ctr = 1;
+       /*
+        * For all subsequent seeding calls, we only need the seed buffer
+        * equal to the security strength of the DRBG. We undo the calculation
+        * in drbg_alloc_state.
+        */
+       if (!reseed)
+               drbg->seed_buf_len = drbg->seed_buf_len / 3 * 2;
 
 out:
-       kzfree(entropy);
        return ret;
 }
 
@@ -1143,6 +1148,8 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
        drbg->prev = NULL;
        drbg->fips_primed = false;
 #endif
+       kzfree(drbg->seed_buf);
+       drbg->seed_buf = NULL;
 }
 
 /*
@@ -1204,6 +1211,26 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
                if (!drbg->scratchpad)
                        goto err;
        }
+
+       /*
+        * Gather entropy equal to the security strength of the DRBG.
+        * With a derivation function, a nonce is required in addition
+        * to the entropy. A nonce must be at least 1/2 of the security
+        * strength of the DRBG in size. Thus, entropy * nonce is 3/2
+        * of the strength. The consideration of a nonce is only
+        * applicable during initial seeding.
+        */
+       drbg->seed_buf_len = drbg_sec_strength(drbg->core->flags);
+       if (!drbg->seed_buf_len) {
+               ret = -EFAULT;
+               goto err;
+       }
+       /* ensure we have sufficient buffer space for initial seed */
+       drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
+       drbg->seed_buf = kzalloc(drbg->seed_buf_len, GFP_KERNEL);
+       if (!drbg->seed_buf)
+               goto err;
+
        return 0;
 
 err: