Use rdrand as additional entropy source.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 25 Dec 2013 15:00:39 +0000 (15:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sat, 11 Jan 2014 14:19:25 +0000 (14:19 +0000)
If available rdrand is used as an additional entropy source for the
PRNG and for additional input in FIPS mode.

crypto/rand/md_rand.c
crypto/rand/rand_lcl.h
crypto/rand/rand_lib.c

index 2d6a55f6edfa7739d332933a52f131b7cf6261d1..7158d30d8fc6cd1bdccc06eba6bfc2effd3d4648 100644 (file)
@@ -167,6 +167,8 @@ int rand_predictable=0;
 
 const char RAND_version[]="RAND" OPENSSL_VERSION_PTEXT;
 
+static void rand_hw_seed(EVP_MD_CTX *ctx);
+
 static void ssleay_rand_cleanup(void);
 static int ssleay_rand_seed(const void *buf, int num);
 static int ssleay_rand_add(const void *buf, int num, double add_entropy);
@@ -531,6 +533,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
                                       sizeof tv))
                                goto err;
                        curr_time = 0;
+                       rand_hw_seed(&m);
                        }
                if (!MD_Update(&m,local_md,MD_DIGEST_LENGTH))
                        goto err;
@@ -663,3 +666,79 @@ static int ssleay_rand_status(void)
        
        return ret;
        }
+
+/* rand_hw_seed: get seed data from any available hardware RNG.
+ * only currently supports rdrand.
+ */
+
+/* Adapted from eng_rdrand.c */
+
+#if (defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
+     defined(__x86_64) || defined(__x86_64__) || \
+     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
+
+#define RDRAND_CALLS   4
+
+size_t OPENSSL_ia32_rdrand(void);
+extern unsigned int OPENSSL_ia32cap_P[];
+
+static void rand_hw_seed(EVP_MD_CTX *ctx)
+       {
+       int i;
+       if (!(OPENSSL_ia32cap_P[1] & (1<<(62-32))))
+               return;
+       for (i = 0; i < RDRAND_CALLS; i++)
+               {
+               size_t rnd;
+               rnd = OPENSSL_ia32_rdrand();
+               if (rnd == 0)
+                       return;
+               MD_Update(ctx, (unsigned char *)rnd, sizeof(size_t));
+               }
+       }
+
+/* XOR an existing buffer with random data */
+
+void rand_hw_xor(unsigned char *buf, size_t num)
+       {
+       size_t rnd;
+       if (!(OPENSSL_ia32cap_P[1] & (1<<(62-32))))
+               return;
+       while (num >= sizeof(size_t))
+               {
+               rnd = OPENSSL_ia32_rdrand();
+               if (rnd == 0)
+                       return;
+               *((size_t *)buf) ^= rnd;
+               buf += sizeof(size_t);
+               num -= sizeof(size_t);
+               }
+       if (num)
+               {
+               rnd = OPENSSL_ia32_rdrand();
+               if (rnd == 0)
+                       return;
+               while(num)
+                       {
+                       *buf ^= rnd & 0xff;
+                       rnd >>= 8;
+                       buf++;
+                       num--;
+                       }
+               }
+       }
+
+
+#else
+
+static void rand_hw_seed(EVP_MD_CTX *ctx)
+       {
+       return;
+       }
+
+void rand_hw_xor(unsigned char *buf, size_t num)
+       {
+       return;
+       }
+
+#endif
index 618a8ec899cec833699fd3f3f5ac0be2caa4d3eb..6696b8057bbe71d532d17bb12ca95afe07ae4f8d 100644 (file)
 #define        MD(a,b,c)               EVP_Digest(a,b,c,NULL,EVP_md2(), NULL)
 #endif
 
+void rand_hw_xor(unsigned char *buf, size_t num);
 
 #endif
index e8957dbb306cc6dbc7d673f7fa0bcfa787559d1a..4aa6486c8102c9e07d64cfd29ca57c76db0ba9ff 100644 (file)
@@ -227,6 +227,7 @@ static size_t drbg_get_adin(DRBG_CTX *ctx, unsigned char **pout)
        static unsigned char buf[16];
        static unsigned long counter;
        FIPS_get_timevec(buf, &counter);
+       rand_hw_xor(buf, sizeof(buf));
        *pout = buf;
        return sizeof(buf);
        }