crypto: drbg - use Jitter RNG to obtain seed
authorStephan Mueller <smueller@chronox.de>
Mon, 25 May 2015 13:09:59 +0000 (15:09 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 27 May 2015 09:51:53 +0000 (17:51 +0800)
During initialization, the DRBG now tries to allocate a handle of the
Jitter RNG. If such a Jitter RNG is available during seeding, the DRBG
pulls the required entropy/nonce string from get_random_bytes and
concatenates it with a string of equal size from the Jitter RNG. That
combined string is now the seed for the DRBG.

Written differently, the initial seed of the DRBG is now:

get_random_bytes(entropy/nonce) || jitterentropy (entropy/nonce)

If the Jitter RNG is not available, the DRBG only seeds from
get_random_bytes.

CC: Andreas Steffen <andreas.steffen@strongswan.org>
CC: Theodore Ts'o <tytso@mit.edu>
CC: Sandy Harris <sandyinchina@gmail.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/drbg.c
include/crypto/drbg.h

index aca86847ea49b49d15cb7790c9feab8bb48d9a2d..92843488af09b36415ebd041a8659377bd78cb92 100644 (file)
@@ -1062,13 +1062,18 @@ static void drbg_async_seed(struct work_struct *work)
        LIST_HEAD(seedlist);
        struct drbg_state *drbg = container_of(work, struct drbg_state,
                                               seed_work);
+       int ret;
 
        get_blocking_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
 
        drbg_string_fill(&data, drbg->seed_buf, drbg->seed_buf_len);
        list_add_tail(&data.list, &seedlist);
        mutex_lock(&drbg->drbg_mutex);
-       __drbg_seed(drbg, &seedlist, true);
+       ret = __drbg_seed(drbg, &seedlist, true);
+       if (!ret && drbg->jent) {
+               crypto_free_rng(drbg->jent);
+               drbg->jent = NULL;
+       }
        memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
        mutex_unlock(&drbg->drbg_mutex);
 }
@@ -1103,10 +1108,24 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                                 drbg->test_data.len);
                pr_devel("DRBG: using test entropy\n");
        } else {
-               pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-                        drbg->seed_buf_len);
+               /* Get seed from in-kernel /dev/urandom */
                get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
-               drbg_string_fill(&data1, drbg->seed_buf, drbg->seed_buf_len);
+
+               /* Get seed from Jitter RNG */
+               if (!drbg->jent ||
+                   crypto_rng_get_bytes(drbg->jent,
+                                        drbg->seed_buf + drbg->seed_buf_len,
+                                        drbg->seed_buf_len)) {
+                       drbg_string_fill(&data1, drbg->seed_buf,
+                                        drbg->seed_buf_len);
+                       pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
+                                drbg->seed_buf_len);
+               } else {
+                       drbg_string_fill(&data1, drbg->seed_buf,
+                                        drbg->seed_buf_len * 2);
+                       pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
+                                drbg->seed_buf_len * 2);
+               }
        }
        list_add_tail(&data1.list, &seedlist);
 
@@ -1131,7 +1150,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
         * 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);
+       memzero_explicit(drbg->seed_buf, drbg->seed_buf_len * 2);
        if (ret)
                goto out;
        /*
@@ -1171,6 +1190,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 #endif
        kzfree(drbg->seed_buf);
        drbg->seed_buf = NULL;
+       if (drbg->jent) {
+               crypto_free_rng(drbg->jent);
+               drbg->jent = NULL;
+       }
 }
 
 /*
@@ -1246,14 +1269,29 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
                ret = -EFAULT;
                goto err;
        }
-       /* ensure we have sufficient buffer space for initial seed */
+       /*
+        * Ensure we have sufficient buffer space for initial seed which
+        * consists of the seed from get_random_bytes and the Jitter RNG.
+        */
        drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
-       drbg->seed_buf = kzalloc(drbg->seed_buf_len, GFP_KERNEL);
+       drbg->seed_buf = kzalloc(drbg->seed_buf_len * 2, GFP_KERNEL);
        if (!drbg->seed_buf)
                goto err;
 
        INIT_WORK(&drbg->seed_work, drbg_async_seed);
 
+       drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+       if(IS_ERR(drbg->jent))
+       {
+               pr_info("DRBG: could not allocate Jitter RNG handle for seeding\n");
+               /*
+                * As the Jitter RNG is a module that may not be present, we
+                * continue with the operation and do not fully tie the DRBG
+                * to the Jitter RNG.
+                */
+               drbg->jent = NULL;
+       }
+
        return 0;
 
 err:
index 46994b25dc859d6cb853ac27600fbbacfe0582e0..c3f208dc83ee6e835faa0c400d3cfdf9b2c92e5b 100644 (file)
@@ -123,6 +123,7 @@ struct drbg_state {
        struct work_struct seed_work;   /* asynchronous seeding support */
        u8 *seed_buf;                   /* buffer holding the seed */
        size_t seed_buf_len;
+       struct crypto_rng *jent;
        const struct drbg_state_ops *d_ops;
        const struct drbg_core *core;
        struct drbg_string test_data;