[PATCH 1/1] Add support for using DRNG random number generator

Dmitry Kasatkin dmitry.kasatkin at intel.com
Mon Dec 17 14:52:44 CET 2012


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 at intel.com>
---
 configure.ac     |   13 ++++++++++++
 random/rndhw.c   |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/g10lib.h     |    1 +
 src/global.c     |    1 +
 src/hwfeatures.c |   30 +++++++++++++++++++++++++++
 5 files changed, 106 insertions(+)

diff --git a/configure.ac b/configure.ac
index ff07dda..7d162a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -544,6 +544,18 @@ if test x"$aesnisupport" = xyes ; then
             [Enable support for Intel AES-NI instructions.])
 fi
 
+# Implementation of the --disable-drng-support switch.
+AC_MSG_CHECKING([whether DRNG support is requested])
+AC_ARG_ENABLE(drng-support,
+              AC_HELP_STRING([--disable-drng-support],
+                 [Disable support for the Intel DRNG (RDRAND instruction)]),
+	      drngsupport=$enableval,drngsupport=yes)
+AC_MSG_RESULT($drngsupport)
+if test x"$drngsupport" = xyes ; then
+  AC_DEFINE(ENABLE_DRNG_SUPPORT, 1,
+            [Enable support for Intel DRNG (RDRAND instruction).])
+fi
+
 # Implementation of the --disable-O-flag-munging switch.
 AC_MSG_CHECKING([whether a -O flag munging is requested])
 AC_ARG_ENABLE([O-flag-munging],
@@ -1304,6 +1316,7 @@ echo "
         Using linux capabilities:  $use_capabilities
         Try using Padlock crypto:  $padlocksupport
         Try using AES-NI crypto:   $aesnisupport
+        Try using DRNG (RDRAND):   $drngsupport
 "
 
 if test "$print_egd_notice" = "yes"; then
diff --git a/random/rndhw.c b/random/rndhw.c
index 775d90f..08f16cc 100644
--- a/random/rndhw.c
+++ b/random/rndhw.c
@@ -34,6 +34,16 @@
 # endif
 #endif /*ENABLE_PADLOCK_SUPPORT*/
 
+#undef USE_DRNG
+#ifdef ENABLE_DRNG_SUPPORT
+# ifdef __GNUC__
+#  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;
@@ -108,6 +118,49 @@ 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);
+
+	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 +178,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 +200,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);
diff --git a/src/g10lib.h b/src/g10lib.h
index f1af399..5e99c46 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -151,6 +151,7 @@ int _gcry_log_verbosity( int level );
 #define HWF_PADLOCK_MMUL 8
 
 #define HWF_INTEL_AESNI  256
+#define HWF_INTEL_RDRAND 512
 
 
 unsigned int _gcry_get_hw_features (void);
diff --git a/src/global.c b/src/global.c
index f280a7b..2428e21 100644
--- a/src/global.c
+++ b/src/global.c
@@ -66,6 +66,7 @@ static struct
     { HWF_PADLOCK_SHA, "padlock-sha" },
     { HWF_PADLOCK_MMUL,"padlock-mmul"},
     { HWF_INTEL_AESNI, "intel-aesni" },
+    { HWF_INTEL_RDRAND,"intel-rdrand" },
     { 0, NULL}
   };
 
diff --git a/src/hwfeatures.c b/src/hwfeatures.c
index 82c435b..e55d9b6 100644
--- a/src/hwfeatures.c
+++ b/src/hwfeatures.c
@@ -134,6 +134,20 @@ detect_x86_64_gnuc (void)
      : "%eax", "%ebx", "%ecx", "%edx", "cc"
      );
 #endif /*#ifdef ENABLE_AESNI_SUPPORT*/
+#ifdef ENABLE_DRNG_SUPPORT
+   asm volatile
+     ("movl $1, %%eax\n\t"           /* Get CPU info and feature flags.  */
+      "cpuid\n"
+      "testl $0x40000000, %%ecx\n\t" /* Test bit 30.  */
+      "jz .Lno_rdrand%=\n\t"         /* No RDRAND support.  */
+      "orl $512, %0\n"               /* Set our HWF_INTEL_RDRAND bit.  */
+
+      ".Lno_rdrand%=:\n"
+      : "+r" (hw_features)
+      :
+      : "%eax", "%ecx", "%edx", "cc"
+      );
+#endif /* #ifdef ENABLE_DRNG_SUPPORT */
 
 }
 #endif /* __x86_64__ && __GNUC__ */
@@ -267,6 +281,22 @@ detect_ia32_gnuc (void)
      : "%eax", "%ecx", "%edx", "cc"
      );
 #endif /*ENABLE_AESNI_SUPPORT*/
+#ifdef ENABLE_DRNG_SUPPORT
+   asm volatile
+     ("pushl %%ebx\n\t"	        /* Save GOT register.  */
+      "movl $1, %%eax\n\t"           /* Get CPU info and feature flags.  */
+      "cpuid\n"
+      "popl %%ebx\n\t"	        /* Restore GOT register. */
+      "testl $0x40000000, %%ecx\n\t" /* Test bit 30.  */
+      "jz .Lno_rdrand%=\n\t"         /* No RDRAND support.  */
+      "orl $512, %0\n"               /* Set our HWF_INTEL_RDRAND bit.  */
+
+      ".Lno_rdrand%=:\n"
+      : "+r" (hw_features)
+      :
+      : "%eax", "%ecx", "%edx", "cc"
+      );
+#endif /*ENABLE_DRNG_SUPPORT*/
 
 }
 #endif /* __i386__ && SIZEOF_UNSIGNED_LONG == 4 && __GNUC__ */
-- 
1.7.10.4




More information about the Gcrypt-devel mailing list