diff options
| author | Jeffrey Walton <noloader@gmail.com> | 2015-11-18 15:19:02 -0500 |
|---|---|---|
| committer | Jeffrey Walton <noloader@gmail.com> | 2015-11-18 15:19:02 -0500 |
| commit | d2fda9bd4231a7dfcb44e59150f11246d992843f (patch) | |
| tree | ae2afc3dd818e907f3035d783f039abf9fc83078 /rdrand.cpp | |
| parent | 1993a8b7b9f60020ce1524860ce76c01081f3e79 (diff) | |
| download | cryptopp-git-d2fda9bd4231a7dfcb44e59150f11246d992843f.tar.gz | |
Cleared issues 11,12,13 (Clang integrated assembler), 58 (RC rollup), 66 (Coverity rollup)
Diffstat (limited to 'rdrand.cpp')
| -rw-r--r-- | rdrand.cpp | 644 |
1 files changed, 162 insertions, 482 deletions
@@ -20,225 +20,163 @@ // available. A lazy throw strategy is used in case the CPU does not support
// the instruction. I.e., the throw is deferred until GenerateBlock is called.
-// For GCC/ICC/Clang on Unix/Linux/Apple, you can use `-mrdrnd` to force the
-// option. If you use `-mrdrnd`, then __RDRND__ is defined and intrinsics
-// are used. If you omit the otion, then assembly language routines are
-// used if the compiler supports RDRAND. The same applies to -mrdseed and
-// __RDSEED__ (but they did not skimp on the extra vowel). Also see
-// http://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions
-
// Here's the naming convention for the functions....
// MSC = Microsoft Compiler (and compatibles)
// GCC = GNU Compiler (and compatibles)
+// ALL = MSC and GCC (and compatibles)
// RRA = RDRAND, Assembly
// RSA = RDSEED, Assembly
// RRI = RDRAND, Intrinsic
// RSA = RDSEED, Intrinsic
-// Helper macros. IA32_ASM captuers the architecture. MSC_RDRAND_COMPILER means
-// MSC_RDSEED_COMPILER; GCC_RDRAND_COMPILER means GCC_RDSEED_COMPILER.
-#define IA32_ASM (!defined(CRYPTOPP_DISABLE_ASM) && (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64))
-#define MSC_RDRAND_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
-#define GCC_RDRAND_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
-#define MSC_RDSEED_COMPILER MSC_RDRAND_COMPILER
-#define GCC_RDSEED_COMPILER GCC_RDRAND_COMPILER
-
-// GCC cannot compile programs with __builtin_ia32_rdseed{16|32|64}_step
-#if __GNUC__
-# define GCC_RDSEED_INTRINSIC_AVAILABLE 0
-#endif
-
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
-// Microsoft uses Intel's intrinsics, and it excludes AMD's CPUs. You should
-// "#define MSC_RDRAND_INTRINSIC_AVAILABLE 0" and
-// "#define MSC_RDSEED_INTRINSIC_AVAILABLE 0", if possible. The downside is
-// you must assemble the object files rdrand-x86.obj and rdrand-x86.obj and
-// then build the rdrand-x86.lib and rdrand-x86.lib libraries. To build the
-// libraries run "make-rdrand.cmd" from a developer prompt.
+// For Linux, install NASM, run rdrand-nasm.asm, add the apppropriate
+// object file to the Makefile's LIBOBJS (rdrand-x{86|32|64}.o). After
+// that, define these. They are not enabled by default because they
+// are not easy to cut-in in the Makefile.
+
+#if 0
+#define NASM_RDRAND_ASM_AVAILABLE 1
+#define NASM_RDSEED_ASM_AVAILABLE 1
+#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
-// MSC Compatible on Windows. Set MSC_RDRAND_ASM_AVAILABLE if it (and Intrinsics)
-// are not set. The requirement is rdrand.asm assembled with MASM/MAS64. We use
-// CRYTPOPP_MSC_VERSION as a proxy for MASM/MAS64 availability.
-#if defined(CRYPTOPP_WIN32_AVAILABLE) && IA32_ASM && defined(CRYTPOPP_MSC_VERSION)
-# if !defined(MSC_RDRAND_ASM_AVAILABLE) && !(MSC_RDRAND_INTRINSIC_AVAILABLE > 0)
-# define MSC_RDRAND_ASM_AVAILABLE 1
-# define MSC_RDRAND_INTRINSIC_AVAILABLE 0
+// According to Wei, CRYPTOPP_DISABLE_ASM is a failsafe due to the assembler.
+// We sidestep it because it does not limit us. The assembler does not limit
+// us because we emit out own byte codes as needed. To diasble RDRAND or
+// RDSEED, set CRYPTOPP_BOOL_RDRAND_ASM or CRYPTOPP_BOOL_RDSEED_ASM to 0.
+#ifndef CRYPTOPP_CPUID_AVAILABLE
+# if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
+# define CRYPTOPP_CPUID_AVAILABLE
# endif
#endif
-// Fallback to MSC_RDRAND_INTRINSIC_AVAILABLE on Windows. The compiler must support it.
-#if defined(CRYPTOPP_WIN32_AVAILABLE) && MSC_RDRAND_COMPILER
-# if !defined(MSC_RDRAND_INTRINSIC_AVAILABLE) && !(MSC_RDRAND_ASM_AVAILABLE > 0)
-# define MSC_RDRAND_INTRINSIC_AVAILABLE 1
-# define MSC_RDRAND_ASM_AVAILABLE 0
-# endif
+#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDRAND_ASM)
+# define CRYPTOPP_BOOL_RDRAND_ASM 1
+#else
+# define CRYPTOPP_BOOL_RDRAND_ASM 0
#endif
-
-// GCC Compatible on Unix/Linux/Apple. Set GCC_RDRAND_INTRINSIC_AVAILABLE if
-// it (and ASM) are not set. The requirements are __RDRND__ preprocessor.
-#if defined(CRYPTOPP_UNIX_AVAILABLE) && GCC_RDRAND_COMPILER && (__RDRND__ >= 1)
-# if !defined(GCC_RDRAND_INTRINSIC_AVAILABLE) && !(defined(GCC_RDRAND_ASM_AVAILABLE) && (GCC_RDRAND_ASM_AVAILABLE > 0))
-# define GCC_RDRAND_INTRINSIC_AVAILABLE 1
-# define GCC_RDRAND_ASM_AVAILABLE 0
-# endif
+#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDSEED_ASM)
+# define CRYPTOPP_BOOL_RDSEED_ASM 1
+#else
+# define CRYPTOPP_BOOL_RDSEED_ASM 0
#endif
-// Fallback to MSC_ASM_INTRINSIC_AVAILABLE on Unix/Linux/Apple
-#if defined(CRYPTOPP_UNIX_AVAILABLE) && IA32_ASM && GCC_RDRAND_COMPILER
-# if !defined(GCC_RDRAND_INTRINSIC_AVAILABLE) && !(defined(GCCC_RDRAND_ASM_AVAILABLE) && (GCCC_RDRAND_ASM_AVAILABLE > 0))
-# define GCC_RDRAND_ASM_AVAILABLE 1
-# define GCC_RDRAND_INTRINSIC_AVAILABLE 0
-# endif
+#if defined(CRYPTOPP_CPUID_AVAILABLE)
+# define MSC_INTRIN_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
+# define GCC_INTRIN_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
+#else
+# define MSC_INTRIN_COMPILER 0
+# define GCC_INTRIN_COMPILER 0
+#endif
+
+// In general, the library's ASM code is best on Windows, and Intrinsics is
+// the best code under GCC and compatibles. We favor them accordingly.
+// The NASM code is optimized well on Linux, but its not easy to cut-in.
+#if defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_MSC_VERSION >= 1200)
+# if CRYPTOPP_BOOL_RDRAND_ASM
+# define MASM_RDRAND_ASM_AVAILABLE 1
+# elif MSC_INTRIN_COMPILER
+# define ALL_RDRAND_INTRIN_AVAILABLE 1
+# endif
+# if CRYPTOPP_BOOL_RDSEED_ASM
+# define MASM_RDSEED_ASM_AVAILABLE 1
+# elif MSC_INTRIN_COMPILER
+# define ALL_RDSEED_INTRIN_AVAILABLE 1
+# endif
+#elif defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_GCC_VERSION >= 30200)
+# if GCC_INTRIN_COMPILER && defined(__RDRND__)
+# define ALL_RDRAND_INTRIN_AVAILABLE 1
+# elif CRYPTOPP_BOOL_RDRAND_ASM
+# define GCC_RDRAND_ASM_AVAILABLE 1
+# endif
+# if GCC_INTRIN_COMPILER && defined(__RDSEED__)
+# define ALL_RDSEED_INTRIN_AVAILABLE 1
+# elif CRYPTOPP_BOOL_RDSEED_ASM
+# define GCC_RDSEED_ASM_AVAILABLE 1
+# endif
+#endif
+
+// Debug diagnostics
+#if !defined(NDEBUG)
+# if MASM_RDRAND_ASM_AVAILABLE
+# pragma message ("MASM_RDRAND_ASM_AVAILABLE is 1")
+# elif NASM_RDRAND_ASM_AVAILABLE
+# pragma message ("NASM_RDRAND_ASM_AVAILABLE is 1")
+# elif GCC_RDRAND_ASM_AVAILABLE
+# pragma message ("GCC_RDRAND_ASM_AVAILABLE is 1")
+# elif ALL_RDRAND_INTRIN_AVAILABLE
+# pragma message ("ALL_RDRAND_INTRIN_AVAILABLE is 1")
+# else
+# pragma message ("RDRAND is not available")
+# endif
+# if MASM_RDSEED_ASM_AVAILABLE
+# pragma message ("MASM_RDSEED_ASM_AVAILABLE is 1")
+# elif NASM_RDSEED_ASM_AVAILABLE
+# pragma message ("NASM_RDSEED_ASM_AVAILABLE is 1")
+# elif GCC_RDSEED_ASM_AVAILABLE
+# pragma message ("GCC_RDSEED_ASM_AVAILABLE is 1")
+# elif ALL_RDSEED_INTRIN_AVAILABLE
+# pragma message ("ALL_RDSEED_INTRIN_AVAILABLE is 1")
+# else
+# pragma message ("RDSEED is not available")
+# endif
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
-// MSC Compatible on Windows. Set MSC_RDRAND_ASM_AVAILABLE if it (and Intrinsics)
-// are not set. The requirement is rdrand.asm assembled with MASM/MAS64. We use
-// CRYTPOPP_MSC_VERSION as a proxy for MASM/MAS64 availability.
-#if defined(CRYPTOPP_WIN32_AVAILABLE) && IA32_ASM && defined(CRYTPOPP_MSC_VERSION)
-# if !defined(MSC_RDSEED_ASM_AVAILABLE) && !(MSC_RDSEED_INTRINSIC_AVAILABLE > 0)
-# define MSC_RDSEED_ASM_AVAILABLE 1
-# define MSC_RDSEED_INTRINSIC_AVAILABLE 0
+#if (ALL_RDRAND_INTRIN_AVAILABLE || ALL_RDSEED_INTRIN_AVAILABLE)
+# include <immintrin.h> // rdrand, MSC, ICC, and GCC
+# if defined(__has_include)
+# if __has_include(<x86intrin.h>)
+# include <x86intrin.h> // rdseed for some compilers, like GCC
+# endif
# endif
#endif
-// Fallback to MSC_RDSEED_INTRINSIC_AVAILABLE on Windows. The compiler must support it.
-#if defined(CRYPTOPP_WIN32_AVAILABLE) && MSC_RDSEED_COMPILER
-# if !defined(MSC_RDSEED_INTRINSIC_AVAILABLE) && !(MSC_RDSEED_ASM_AVAILABLE > 0)
-# define MSC_RDSEED_INTRINSIC_AVAILABLE 1
-# define MSC_RDSEED_ASM_AVAILABLE 0
-# endif
-#endif
-
-// GCC Compatible on Unix/Linux/Apple. Set GCC_RDSEED_INTRINSIC_AVAILABLE if
-// it (and ASM) are not set. The requirements are __RDSEED__ preprocessor.
-#if defined(CRYPTOPP_UNIX_AVAILABLE) && GCC_RDSEED_COMPILER && (__RDSEED__ >= 1)
-# if !defined(GCC_RDSEED_INTRINSIC_AVAILABLE) && !(defined(GCC_RDSEED_ASM_AVAILABLE) && (GCC_RDSEED_ASM_AVAILABLE > 0))
-# define GCC_RDSEED_INTRINSIC_AVAILABLE 1
-# define GCC_RDSEED_ASM_AVAILABLE 0
-# endif
-#endif
-
-// Fallback to MSC_ASM_INTRINSIC_AVAILABLE on Unix/Linux/Apple
-#if defined(CRYPTOPP_UNIX_AVAILABLE) && IA32_ASM && GCC_RDSEED_COMPILER
-# if !defined(GCC_RDSEED_INTRINSIC_AVAILABLE) && !(defined(GCCC_RDSEED_ASM_AVAILABLE) && (GCCC_RDSEED_ASM_AVAILABLE > 0))
-# define GCC_RDSEED_ASM_AVAILABLE 1
-# define GCC_RDSEED_INTRINSIC_AVAILABLE 0
-# endif
-#endif
-
-/////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////
-
-#if MSC_RDRAND_ASM_AVAILABLE
+#if MASM_RDRAND_ASM_AVAILABLE
# ifdef _M_X64
-extern "C" int CRYPTOPP_FASTCALL MSC_RRA_GenerateBlock(byte*, size_t, unsigned int);
+extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x64.lib")
# else
-extern "C" int MSC_RRA_GenerateBlock(byte*, size_t, unsigned int);
+extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x86.lib")
# endif
#endif
-#if MSC_RDSEED_ASM_AVAILABLE
+#if MASM_RDSEED_ASM_AVAILABLE
# ifdef _M_X64
-extern "C" int CRYPTOPP_FASTCALL MSC_RSA_GenerateBlock(byte*, size_t, unsigned int);
+extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x64.lib")
# else
-extern "C" int MSC_RSA_GenerateBlock(byte*, size_t, unsigned int);
+extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x86.lib")
# endif
#endif
-/////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////
-
-#if MSC_RDRAND_INTRINSIC_AVAILABLE || MSC_RDSEED_INTRINSIC_AVAILABLE
-# include <immintrin.h>
-#elif GCC_RDRAND_INTRINSIC_AVAILABLE || GCC_RDSEED_INTRINSIC_AVAILABLE
-# include <emmintrin.h>
-#endif
-
-// Define ERROR_DEV_NOT_EXIST for this TU if not already defined
-#ifndef ERROR_DEV_NOT_EXIST
-# define ERROR_DEV_NOT_EXIST 0x37
+#if NASM_RDRAND_ASM_AVAILABLE
+extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
#endif
-#if defined(CRYPTOPP_UNIX_AVAILABLE)
-# include <errno.h>
+#if NASM_RDSEED_ASM_AVAILABLE
+extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
#endif
-
-NAMESPACE_BEGIN(CryptoPP)
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
-extern CRYPTOPP_DLL bool CpuId(word32 input, word32 *output);
-#endif
-
-/////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////
-
-// Intel and AMD provide RDRAND, only Intel provides RDSEED. To call these
-// functions, use the word32 array returned from CpuId(0, output[]).
-
-static bool IsIntel(const word32 output[4])
-{
- // This is the "GenuineIntel" string
- return (output[1] /*EBX*/ == 0x756e6547) &&
- (output[2] /*ECX*/ == 0x6c65746e) &&
- (output[3] /*EDX*/ == 0x49656e69);
-}
-
-static bool IsAMD(const word32 output[4])
-{
- // This is the "AuthenticAMD" string
- return (output[1] /*EBX*/ == 0x68747541) &&
- (output[2] /*ECX*/ == 0x69746E65) &&
- (output[3] /*EDX*/ == 0x444D4163);
-}
-
-/////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////
-
-static bool RDRAND_Runtime_Helper()
-{
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
- bool rdrand = false; word32 output[4];
- if (CpuId(0, output))
- {
- if (IsIntel(output) || IsAMD(output))
- {
- if (output[0] /*EAX*/ >= 1 && CpuId(1, output))
- {
- static const unsigned int RDRAND_FLAG = (1 << 30);
- rdrand = !!(output[2] /*ECX*/ & RDRAND_FLAG);
- }
- }
- }
- return rdrand;
-#else
- return false;
-#endif
-}
-
-// This will be moved to CPU.h/CPU.cpp eventually
-static bool hasRDRAND = RDRAND_Runtime_Helper();
-
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
+NAMESPACE_BEGIN(CryptoPP)
-#if MSC_RDRAND_INTRINSIC_AVAILABLE
-static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
+#if ALL_RDRAND_INTRIN_AVAILABLE
+static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
-#if CRYPTOPP_BOOL_X64
+ assert((output && size) || !(output || size));
+#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
word64 val;
#else
word32 val;
@@ -246,7 +184,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety) while (size >= sizeof(val))
{
-#if CRYPTOPP_BOOL_X64
+#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
if (_rdrand64_step((word64*)output))
#else
if (_rdrand32_step((word32*)output))
@@ -264,7 +202,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety) if (size)
{
-#if CRYPTOPP_BOOL_X64
+#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
if (_rdrand64_step(&val))
#else
if (_rdrand32_step(&val))
@@ -280,7 +218,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety) }
}
-#if CRYPTOPP_BOOL_X64
+#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
*((volatile word64*)&val) = 0;
#else
*((volatile word32*)&val) = 0;
@@ -288,68 +226,12 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety) return int(size == 0);
}
-
-#endif // MSC_RDRAND_INTRINSIC_AVAILABLE
-
-#if GCC_RDRAND_INTRINSIC_AVAILABLE
-static int GCC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
-{
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- word64 val;
-#else // CRYPTOPP_BOOL_X86
- word32 val;
-#endif
-
- while (size >= sizeof(val))
- {
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- if (__builtin_ia32_rdrand64_step((word64*)output))
-#else
- if (__builtin_ia32_rdrand32_step((word32*)output))
-#endif
- {
- output += sizeof(val);
- size -= sizeof(val);
- }
- else
- {
- if (!safety--)
- return 0;
- }
- }
-
- if (size)
- {
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- if (__builtin_ia32_rdrand64_step(&val))
-#else
- if (__builtin_ia32_rdrand32_step(&val))
-#endif
- {
- memcpy(output, &val, size);
- size = 0;
- }
- else
- {
- if (!safety--)
- return 0;
- }
- }
-
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- *((volatile word64*)&val) = 0;
-#else
- *((volatile word32*)&val) = 0;
-#endif
-
- return int(size == 0);
-}
-
-#endif // GCC_RDRAND_INTRINSIC_AVAILABLE
+#endif // ALL_RDRAND_INTRINSIC_AVAILABLE
#if GCC_RDRAND_ASM_AVAILABLE
static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
+ assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
@@ -359,9 +241,13 @@ static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety) while (size)
{
__asm__ volatile(
- "rdrand %0; "
+#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
+ ".byte 0x48, 0x0f, 0xc7, 0xf0;\n" // rdrand rax
+#else
+ ".byte 0x0f, 0xc7, 0xf0;\n" // rdrand eax
+#endif
"setc %1; "
- : "=r" (val), "=qm" (rc)
+ : "=a" (val), "=qm" (rc)
:
: "cc"
);
@@ -404,103 +290,39 @@ static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety) #endif // GCC_RDRAND_ASM_AVAILABLE
-#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
-
-//! generate random array of bytes
+#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
void RDRAND::GenerateBlock(byte *output, size_t size)
{
- assert((output == NULL && size == 0) || (output != NULL && size != 0));
- assert(Available());
+ CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
+ assert((output && size) || !(output || size));
- // We could (should?) test Ready, but Available conveys more useful information.
- if(!Available())
+ if(!HasRDRAND())
throw NotImplemented("RDRAND: rdrand is not available on this platform");
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
int rc; CRYPTOPP_UNUSED(rc);
-#if MSC_RDRAND_ASM_AVAILABLE
- rc = MSC_RRA_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDRAND_Err("MSC_RRA_GenerateBlock"); }
+#if MASM_RDRAND_ASM_AVAILABLE
+ rc = MASM_RRA_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDRAND_Err("MASM_RRA_GenerateBlock"); }
+#elif NASM_RDRAND_ASM_AVAILABLE
+ rc = NASM_RRA_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDRAND_Err("NASM_RRA_GenerateBlock"); }
+#elif ALL_RDRAND_INTRIN_AVAILABLE
+ rc = ALL_RRI_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDRAND_Err("ALL_RRI_GenerateBlock"); }
#elif GCC_RDRAND_ASM_AVAILABLE
rc = GCC_RRA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("GCC_RRA_GenerateBlock"); }
-#elif MSC_RDRAND_INTRINSIC_AVAILABLE
- rc = MSC_RRI_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDRAND_Err("MSC_RRI_GenerateBlock"); }
-#elif GCC_RDRAND_INTRINSIC_AVAILABLE
- rc = GCC_RRI_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDRAND_Err("GCC_RRI_GenerateBlock"); }
-#elif (__RDRND__ >= 1)
- // RDRAND detected at compile time, GCC Compatible compiler, but no suitable implementations
-# error "Please report on the Crypto++ user group"
#else
// RDRAND not detected at compile time, and no suitable compiler found
throw NotImplemented("RDRAND: failed to find a suitable implementation???");
-#endif
-
-#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
-}
-
-//! returns true if RDRAND is present or available according to CPUID, false otherwise
-bool RDRAND::Available() const
-{
- word64 unused;
- return Available(unused);
-}
-
-//! returns true if RDRAND is present or available according to CPUID, false otherwise. There is no exended information available.
-bool RDRAND::Available(word64& extendedInfo) const
-{
- if (hasRDRAND)
- {
- extendedInfo = 0;
- return true;
- }
-
-#if defined(CRYPTOPP_WIN32_AVAILABLE)
- extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
-#elif defined(CRYPTOPP_UNIX_AVAILABLE)
- extendedInfo = ENODEV; // 19
-#else
- extendedInfo = word64(-1);
-#endif
-
- return false;
-}
-
-//! returns true if RDRAND is online/ready to produce random numbers, false otherwise
-bool RDRAND::Ready() const
-{
- word64 unused;
- return Ready(unused);
+#endif // CRYPTOPP_CPUID_AVAILABLE
}
-//! returns true if RDRAND is online/ready to produce random numbers, false otherwise. There is no exended information available.
-bool RDRAND::Ready(word64& extendedInfo) const
-{
- if (hasRDRAND)
- {
- extendedInfo = 0;
- return true;
- }
-
-#if defined(CRYPTOPP_WIN32_AVAILABLE)
- extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
-#elif defined(CRYPTOPP_UNIX_AVAILABLE)
- extendedInfo = ENODEV; // 19
-#else
- extendedInfo = word64(-1);
-#endif
-
- return false;
-}
-
-//! generate and discard n bytes.
void RDRAND::DiscardBytes(size_t n)
-{
+{
// RoundUpToMultipleOf is used because a full word is read, and its cheaper
// to discard full words. There's no sense in dealing with tail bytes.
- assert(Ready());
+ assert(HasRDRAND());
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
FixedSizeSecBlock<word64, 16> discard;
n = RoundUpToMultipleOf(n, sizeof(word64));
@@ -517,41 +339,16 @@ void RDRAND::DiscardBytes(size_t n) count = STDMIN(n, discard.SizeInBytes());
}
}
+#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
-static bool RDSEED_Runtime_Helper()
+#if ALL_RDSEED_INTRIN_AVAILABLE
+static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
- bool rdseed = false; word32 output[4];
- if (CpuId(0, output))
- {
- // Only Intel supports RDSEED at the moment.
- if (IsIntel(output))
- {
- if (output[0] /*EAX*/ >= 7 && CpuId(7, output))
- {
- static const unsigned int RDSEED_FLAG = (1 << 18);
- rdseed = !!(output[1] /*EBX*/ & RDSEED_FLAG);
- }
- }
- }
- return rdseed;
-#else
- return false;
-#endif
-}
-
-// This will be moved to CPU.h/CPU.cpp eventually
-static bool hasRDSEED = RDSEED_Runtime_Helper();
-
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
-
-#if MSC_RDSEED_INTRINSIC_AVAILABLE
-static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
-{
-#if CRYPTOPP_BOOL_X64
+ assert((output && size) || !(output || size));
+#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
word32 val;
@@ -559,7 +356,7 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety) while (size >= sizeof(val))
{
-#if CRYPTOPP_BOOL_X64
+#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (_rdseed64_step((word64*)output))
#else
if (_rdseed32_step((word32*)output))
@@ -577,7 +374,7 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety) if (size)
{
-#if CRYPTOPP_BOOL_X64
+#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (_rdseed64_step(&val))
#else
if (_rdseed32_step(&val))
@@ -593,62 +390,6 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety) }
}
-#if CRYPTOPP_BOOL_X64
- *((volatile word64*)&val) = 0;
-#else
- *((volatile word32*)&val) = 0;
-#endif
-
- return int(size == 0);
-}
-
-#endif // MSC_RDSEED_INTRINSIC_AVAILABLE
-
-#if GCC_RDSEED_INTRINSIC_AVAILABLE
-static int GCC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
-{
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- word64 val;
-#else // CRYPTOPP_BOOL_X86
- word32 val;
-#endif
-
- while (size >= sizeof(val))
- {
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- if (__builtin_ia32_rdseed64_step((word64*)output))
-#else
- if (__builtin_ia32_rdseed32_step((word32*)output))
-#endif
- {
- output += sizeof(val);
- size -= sizeof(val);
- }
- else
- {
- if (!safety--)
- return 0;
- }
- }
-
- if (size)
- {
-#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
- if (__builtin_ia32_rdseed64_step(&val))
-#else
- if (__builtin_ia32_rdseed32_step(&val))
-#endif
- {
- memcpy(output, &val, size);
- size = 0;
- }
- else
- {
- if (!safety--)
- return 0;
- }
- }
-
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
*((volatile word64*)&val) = 0;
#else
@@ -657,12 +398,12 @@ static int GCC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety) return int(size == 0);
}
-
-#endif // GCC_RDSEED_INTRINSIC_AVAILABLE
+#endif // ALL_RDSEED_INTRIN_AVAILABLE
#if GCC_RDSEED_ASM_AVAILABLE
static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
+ assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
@@ -672,9 +413,13 @@ static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety) while (size)
{
__asm__ volatile(
- "rdseed %0; "
+#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
+ ".byte 0x48, 0x0f, 0xc7, 0xf8;\n" // rdseed rax
+#else
+ ".byte 0x0f, 0xc7, 0xf8;\n" // rdseed eax
+#endif
"setc %1; "
- : "=r" (val), "=qm" (rc)
+ : "=a" (val), "=qm" (rc)
:
: "cc"
);
@@ -714,107 +459,41 @@ static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety) return int(size == 0);
}
-
#endif // GCC_RDSEED_ASM_AVAILABLE
-#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
-
-//! generate random array of bytes
+#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
void RDSEED::GenerateBlock(byte *output, size_t size)
{
CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
- assert((output == NULL && size == 0) || (output != NULL && size != 0));
- assert(Available());
+ assert((output && size) || !(output || size));
- // We could (should?) test Ready, but Available conveys more useful information.
- if(!Available())
+ if(!HasRDSEED())
throw NotImplemented("RDSEED: rdseed is not available on this platform");
-#if defined(CRYPTOPP_CPUID_AVAILABLE)
int rc; CRYPTOPP_UNUSED(rc);
-#if MSC_RDSEED_ASM_AVAILABLE
- rc = MSC_RSA_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDSEED_Err("MSC_RSA_GenerateBlock"); }
+#if MASM_RDSEED_ASM_AVAILABLE
+ rc = MASM_RSA_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDSEED_Err("MASM_RSA_GenerateBlock"); }
+#elif NASM_RDSEED_ASM_AVAILABLE
+ rc = NASM_RSA_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDRAND_Err("NASM_RSA_GenerateBlock"); }
+#elif ALL_RDSEED_INTRIN_AVAILABLE
+ rc = ALL_RSI_GenerateBlock(output, size, m_retries);
+ if (!rc) { throw RDSEED_Err("ALL_RSI_GenerateBlock"); }
#elif GCC_RDSEED_ASM_AVAILABLE
rc = GCC_RSA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("GCC_RSA_GenerateBlock"); }
-#elif MSC_RDSEED_INTRINSIC_AVAILABLE
- rc = MSC_RSI_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDSEED_Err("MSC_RSI_GenerateBlock"); }
-#elif GCC_RDSEED_INTRINSIC_AVAILABLE
- rc = GCC_RSI_GenerateBlock(output, size, m_retries);
- if (!rc) { throw RDSEED_Err("GCC_RSI_GenerateBlock"); }
-#elif (__RDSEED__ >= 1)
- // RDSEED detected at compile time, GCC Compatible compiler, but no suitable implementations
-# error "Please report on the Crypto++ user group"
#else
// RDSEED not detected at compile time, and no suitable compiler found
throw NotImplemented("RDSEED: failed to find a suitable implementation???");
#endif
-
-#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
-}
-
-//! returns true if RDSEED is present or available according to CPUID, false otherwise
-bool RDSEED::Available() const
-{
- word64 unused;
- return Available(unused);
-}
-
-//! returns true if RDSEED is present or available according to CPUID, false otherwise. There is no exended information available.
-bool RDSEED::Available(word64& extendedInfo) const
-{
- if (hasRDSEED)
- {
- extendedInfo = 0;
- return true;
- }
-
-#if defined(CRYPTOPP_WIN32_AVAILABLE)
- extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
-#elif defined(CRYPTOPP_UNIX_AVAILABLE)
- extendedInfo = ENODEV; // 19
-#else
- extendedInfo = word64(-1);
-#endif
-
- return false;
-}
-
-//! returns true if RDSEED is online/ready to produce random numbers, false otherwise
-bool RDSEED::Ready() const
-{
- word64 unused;
- return Ready(unused);
}
-//! returns true if RDSEED is online/ready to produce random numbers, false otherwise. There is no exended information available.
-bool RDSEED::Ready(word64& extendedInfo) const
-{
- if (hasRDSEED)
- {
- extendedInfo = 0;
- return true;
- }
-
-#if defined(CRYPTOPP_WIN32_AVAILABLE)
- extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
-#elif defined(CRYPTOPP_UNIX_AVAILABLE)
- extendedInfo = ENODEV; // 19
-#else
- extendedInfo = word64(-1);
-#endif
-
- return false;
-}
-
-//! generate and discard n bytes.
void RDSEED::DiscardBytes(size_t n)
-{
+{
// RoundUpToMultipleOf is used because a full word is read, and its cheaper
// to discard full words. There's no sense in dealing with tail bytes.
- assert(Ready());
+ assert(HasRDSEED());
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
FixedSizeSecBlock<word64, 16> discard;
n = RoundUpToMultipleOf(n, sizeof(word64));
@@ -831,5 +510,6 @@ void RDSEED::DiscardBytes(size_t n) count = STDMIN(n, discard.SizeInBytes());
}
}
+#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
NAMESPACE_END
|
