aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2014-02-24 13:35:48 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2014-02-24 16:52:06 -0800
commit62dec321e2f6cc5de249d1396aec579729d0cf13 (patch)
treeec837d4a70c68a634a656ab1eac32b23041b8b6d
parent908d733527a361621da88cdf931a71aa83cba430 (diff)
downloadrng-tools-62dec321e2f6cc5de249d1396aec579729d0cf13.tar.gz
rngd_rdrand: Code style cleanups
Break up the code into smaller functions for readability, make the code conform a little closer to Linux standard, and try to reduce the number of #ifdefs. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--rngd_rdrand.c195
1 files changed, 104 insertions, 91 deletions
diff --git a/rngd_rdrand.c b/rngd_rdrand.c
index 8d469b9..9a20d7d 100644
--- a/rngd_rdrand.c
+++ b/rngd_rdrand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Intel Corporation
+ * Copyright (c) 2012-2014, Intel Corporation
* Authors: Richard B. Hill <richard.b.hill@intel.com>,
* H. Peter Anvin <hpa@linux.intel.com>,
* John P. Mechalas <john.p.mechalas@intel.com>
@@ -59,26 +59,32 @@ extern int x86_rdrand_nlong(void *ptr, size_t count);
extern void x86_aes_mangle(void *data, void *state);
/* Checking eflags to confirm cpuid instruction available */
-/* Only necessary for 32 bit processors */
-#if defined (__i386__)
-static int x86_has_eflag(uint32_t flag)
+static inline int x86_has_eflag(unsigned long flag)
{
- uint32_t f0, f1;
- asm("pushfl ; "
- "pushfl ; "
- "popl %0 ; "
- "movl %0,%1 ; "
- "xorl %2,%1 ; "
- "pushl %1 ; "
- "popfl ; "
- "pushfl ; "
- "popl %1 ; "
- "popfl"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
- return !!((f0^f1) & flag);
+ unsigned long f0, f1;
+ asm("pushf ; "
+ "pushf ; "
+ "pop %0 ; "
+ "mov %0,%1 ; "
+ "xor %2,%1 ; "
+ "push %1 ; "
+ "popf ; "
+ "pushf ; "
+ "pop %1 ; "
+ "popf"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+ return !!((f0^f1) & flag);
}
+
+static inline int x86_has_cpuid(void)
+{
+#ifdef __i386__
+ return x86_has_eflag(1 << 21); /* ID flag */
+#else
+ return 1; /* x86-64 always has CPUID */
#endif
+}
/* Calling cpuid instruction to verify rdrand and aes-ni capability */
static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
@@ -105,7 +111,7 @@ static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
#define CHUNK_SIZE (16*8)
static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128)));
-static int have_aesni= 0;
+static int have_aesni;
/* Necessary if we have RDRAND but not AES-NI */
@@ -115,15 +121,29 @@ static int have_aesni= 0;
static gcry_cipher_hd_t gcry_cipher_hd;
-/* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */
+#endif
-static const unsigned char key[16]= {
- 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
- 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
-};
+static inline int gcrypt_mangle(unsigned char *tmp)
+{
+#ifdef HAVE_LIBGCRYPT
+ gcry_error_t gcry_error;
-#endif
+ /* Encrypt tmp in-place. */
+ gcry_error = gcry_cipher_encrypt(gcry_cipher_hd, tmp, CHUNK_SIZE,
+ NULL, 0);
+
+ if (gcry_error) {
+ message(LOG_DAEMON|LOG_ERR,
+ "gcry_cipher_encrypt error: %s\n",
+ gcry_strerror(gcry_error));
+ return -1;
+ }
+ return 0;
+#else
+ return -1;
+#endif
+}
int xread_drng(void *buf, size_t size, struct rng *ent_src)
{
@@ -140,28 +160,14 @@ int xread_drng(void *buf, size_t size, struct rng *ent_src)
return -1;
}
- // Use 128-bit AES in CBC mode to mangle our random data
-
- if ( have_aesni ) x86_aes_mangle(tmp, iv_buf);
- else {
-#ifdef HAVE_LIBGCRYPT
- gcry_error_t gcry_error;
-
- /* Encrypt tmp in-place. */
-
- gcry_error= gcry_cipher_encrypt(gcry_cipher_hd,
- tmp, CHUNK_SIZE, NULL, 0);
-
- if ( gcry_error ) {
- message(LOG_DAEMON|LOG_ERR,
- "gcry_cipher_encrypt error: %s\n",
- gcry_strerror(gcry_error));
- return -1;
- }
-#else
+ /*
+ * Use 128-bit AES in CBC mode to reduce the
+ * data by a factor of rdrand_round_count
+ */
+ if (have_aesni)
+ x86_aes_mangle(tmp, iv_buf);
+ else if (gcrypt_mangle(tmp))
return -1;
-#endif
- }
}
chunk = (sizeof(tmp) > size) ? size : sizeof(tmp);
memcpy(p, tmp, chunk);
@@ -172,6 +178,50 @@ int xread_drng(void *buf, size_t size, struct rng *ent_src)
return 0;
}
+static int init_gcrypt(void)
+{
+#ifdef HAVE_LIBGCRYPT
+ /* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */
+ static const unsigned char key[16] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
+ };
+ gcry_error_t gcry_error;
+
+ if (!gcry_check_version(MIN_GCRYPT_VERSION)) {
+ message(LOG_DAEMON|LOG_ERR,
+ "libgcrypt version mismatch: have %s, require >= %s\n",
+ gcry_check_version(NULL), MIN_GCRYPT_VERSION);
+ return 1;
+ }
+
+ gcry_error = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128,
+ GCRY_CIPHER_MODE_CBC, 0);
+
+ if (!gcry_error)
+ gcry_error = gcry_cipher_setkey(gcry_cipher_hd, key, 16);
+
+ if (!gcry_error) {
+ /*
+ * Only need the first 16 bytes of iv_buf. AES-NI can
+ * encrypt multiple blocks in parallel but we can't.
+ */
+ gcry_error = gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
+ }
+
+ if (gcry_error) {
+ message(LOG_DAEMON|LOG_ERR,
+ "could not set key or IV: %s\n",
+ gcry_strerror(gcry_error));
+ gcry_cipher_close(gcry_cipher_hd);
+ return 1;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
/*
* Confirm RDRAND capabilities for drng entropy source
*/
@@ -180,65 +230,28 @@ int init_drng_entropy_source(struct rng *ent_src)
struct cpuid info;
/* We need RDRAND, but AESni is optional */
const uint32_t features_ecx1_rdrand = 1 << 30;
- const uint32_t features_ecx1_aesni = 1 << 25;
+ const uint32_t features_ecx1_aesni = 1 << 25;
-#if defined(__i386__)
- if (!x86_has_eflag(1 << 21))
+ if (!x86_has_cpuid())
return 1; /* No CPUID instruction */
-#endif
cpuid(0, 0, &info);
if (info.eax < 1)
return 1;
cpuid(1, 0, &info);
- if (! (info.ecx & features_ecx1_rdrand) )
+ if (!(info.ecx & features_ecx1_rdrand))
return 1;
- have_aesni= (info.ecx & features_ecx1_aesni) ? 1 : 0;
-#ifndef HAVE_LIBGCRYPT
- if ( ! have_aesni ) return 1;
-#endif
+ have_aesni = !!(info.ecx & features_ecx1_aesni);
+
+ /* Initialize the AES key */
/* Initialize the IV buffer */
if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(long)))
return 1;
-#ifdef HAVE_LIBGCRYPT
- if ( ! have_aesni ) {
- gcry_error_t gcry_error;
-
- if (! gcry_check_version(MIN_GCRYPT_VERSION) ) {
- message(LOG_DAEMON|LOG_ERR,
- "libgcrypt version mismatch: have %s, require >= %s\n",
- gcry_check_version(NULL), MIN_GCRYPT_VERSION);
- return 1;
- }
-
- gcry_error= gcry_cipher_open(&gcry_cipher_hd,
- GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
-
- if ( ! gcry_error ) {
- gcry_error= gcry_cipher_setkey(gcry_cipher_hd, key, 16);
- }
-
- if ( ! gcry_error ) {
- /*
- * Only need the first 16 bytes of iv_buf. AES-NI can
- * encrypt multiple blocks in parallel but we can't.
- */
-
- gcry_error= gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
- }
-
- if ( gcry_error ) {
- message(LOG_DAEMON|LOG_ERR,
- "could not set key or IV: %s\n",
- gcry_strerror(gcry_error));
- gcry_cipher_close(gcry_cipher_hd);
- return 1;
- }
- }
-#endif
+ if (!have_aesni && init_gcrypt())
+ return 1; /* We need one crypto or the other... */
src_list_add(ent_src);
/* Bootstrap FIPS tests */