diff options
author | Dmitry Kasatkin <dmitry.kasatkin@intel.com> | 2012-12-18 14:56:48 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2012-12-18 19:33:04 +0100 |
commit | efd7002188e6d50013e4d9a920a8b9afa9d210e5 (patch) | |
tree | 09adb14c6f19c50a45ae5c2fb3067c08435506d5 /random | |
parent | bfe4dc11bb822cbc5bf2b425e5a5a2867a904518 (diff) | |
download | libgcrypt-efd7002188e6d50013e4d9a920a8b9afa9d210e5.tar.gz |
Add support for using DRNG random number generator
* configure.ac: Add option --disable-drng-support.
(ENABLE_DRNG_SUPPORT): New.
* random/rndhw.c (USE_DRNG): New.
(rdrand_long, rdrand_nlong, poll_drng): New.
(_gcry_rndhw_poll_fast, _gcry_rndhw_poll_slow): Call poll function.
* src/g10lib.h (HWF_INTEL_RDRAND): New.
* src/global.c (hwflist): Add "intel-rdrand".
* src/hwfeatures.c (detect_x86_64_gnuc) [ENABLE_DRNG_SUPPORT]: Detect
RDRAND.
(detect_ia32_gnuc) [ENABLE_DRNG_SUPPORT]: Detect RDRAND.
--
This patch provides support for using Digital Random Number Generator (DRNG)
engine, which is available on the latest Intel's CPUs. DRNG engine is
accesible via new the RDRAND instruction.
This patch adds the following:
- support for disabling using of rdrand instruction
- checking for RDRAND instruction support using cpuid
- RDRAND usage implementation
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
ChangeLog and editorial changes by wk.
Diffstat (limited to 'random')
-rw-r--r-- | random/rndhw.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/random/rndhw.c b/random/rndhw.c index 775d90f0..cbb28d1a 100644 --- a/random/rndhw.c +++ b/random/rndhw.c @@ -1,5 +1,6 @@ /* rndhw.c - Access to the external random daemon * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2012 Dmitry Kasatkin * * This file is part of Libgcrypt. * @@ -34,6 +35,16 @@ # endif #endif /*ENABLE_PADLOCK_SUPPORT*/ +#undef USE_DRNG +#ifdef ENABLE_DRNG_SUPPORT +# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__) +# define USE_DRNG 1 +# endif +# endif +#endif /*ENABLE_RDRAND_SUPPORT*/ + +typedef void (*add_fn_t)(const void*, size_t, enum random_origins); /* Keep track on whether the RNG has problems. */ static volatile int rng_failed; @@ -109,6 +120,55 @@ poll_padlock (void (*add)(const void*, size_t, enum random_origins), #endif /*USE_PADLOCK*/ +#ifdef USE_DRNG +# define RDRAND_RETRY_LOOPS 10 +# define RDRAND_INT ".byte 0x0f,0xc7,0xf0" +# ifdef __x86_64__ +# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0" +# else +# define RDRAND_LONG RDRAND_INT +# endif +static inline int +rdrand_long (unsigned long *v) +{ + int ok; + asm volatile ("1: " RDRAND_LONG "\n\t" + "jc 2f\n\t" + "decl %0\n\t" + "jnz 1b\n\t" + "2:" + : "=r" (ok), "=a" (*v) + : "0" (RDRAND_RETRY_LOOPS)); + return ok; +} + + +static inline int +rdrand_nlong (unsigned long *v, int count) +{ + while (count--) + if (!rdrand_long(v++)) + return 0; + return 1; +} + + +static size_t +poll_drng (add_fn_t add, enum random_origins origin, int fast) +{ + volatile char buffer[64] __attribute__ ((aligned (8))); + unsigned int nbytes = sizeof (buffer); + + (void)fast; + + if (!rdrand_nlong ((unsigned long *)buffer, sizeof(buffer)/sizeof(long))) + return 0; + (*add)((void *)buffer, nbytes, origin); + return nbytes; +} +#endif /*USE_DRNG*/ + + int _gcry_rndhw_failed_p (void) { @@ -125,6 +185,10 @@ _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, enum random_origins), (void)add; (void)origin; +#ifdef USE_DRNG + if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND)) + poll_drng (add, origin, 1); +#endif #ifdef USE_PADLOCK if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) poll_padlock (add, origin, 1); @@ -143,6 +207,10 @@ _gcry_rndhw_poll_slow (void (*add)(const void*, size_t, enum random_origins), (void)add; (void)origin; +#ifdef USE_DRNG + if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND)) + nbytes += poll_drng (add, origin, 0); +#endif #ifdef USE_PADLOCK if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) nbytes += poll_padlock (add, origin, 0); |