diff --git a/crypto/rand/md_rand.c b/crypto/rand/md_rand.c index 2d6a55f6edfa7739d332933a52f131b7cf6261d1..7158d30d8fc6cd1bdccc06eba6bfc2effd3d4648 100644 --- a/crypto/rand/md_rand.c +++ b/crypto/rand/md_rand.c @@ -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 diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h index 618a8ec899cec833699fd3f3f5ac0be2caa4d3eb..6696b8057bbe71d532d17bb12ca95afe07ae4f8d 100644 --- a/crypto/rand/rand_lcl.h +++ b/crypto/rand/rand_lcl.h @@ -154,5 +154,6 @@ #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 diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index e8957dbb306cc6dbc7d673f7fa0bcfa787559d1a..4aa6486c8102c9e07d64cfd29ca57c76db0ba9ff 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -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); }