]> git.ipfire.org Git - thirdparty/rng-tools.git/commitdiff
rngd_rdrand: Code style cleanups
authorH. Peter Anvin <hpa@linux.intel.com>
Mon, 24 Feb 2014 21:35:48 +0000 (13:35 -0800)
committerH. Peter Anvin <hpa@linux.intel.com>
Tue, 25 Feb 2014 00:52:06 +0000 (16:52 -0800)
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>
rngd_rdrand.c

index 8d469b9523a7018ab62e45a3a4cdc0838d22bd67..9a20d7db0121fcc21861b36c59619dcf3bd1b0fe 100644 (file)
@@ -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 */