diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-24 13:35:48 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-24 16:52:06 -0800 |
commit | 62dec321e2f6cc5de249d1396aec579729d0cf13 (patch) | |
tree | ec837d4a70c68a634a656ab1eac32b23041b8b6d | |
parent | 908d733527a361621da88cdf931a71aa83cba430 (diff) | |
download | rng-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.c | 195 |
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 */ |