diff options
Diffstat (limited to 'external/crypto++-5.6.3/rdrand.cpp')
| -rw-r--r-- | external/crypto++-5.6.3/rdrand.cpp | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/external/crypto++-5.6.3/rdrand.cpp b/external/crypto++-5.6.3/rdrand.cpp new file mode 100644 index 0000000..fb4f477 --- /dev/null +++ b/external/crypto++-5.6.3/rdrand.cpp @@ -0,0 +1,515 @@ +// rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. +// Copyright assigned to Crypto++ project. + +#include "pch.h" +#include "config.h" +#include "cryptlib.h" +#include "secblock.h" +#include "rdrand.h" +#include "cpu.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100) +#endif + +// This file (and friends) provides both RDRAND and RDSEED, but its somewhat +// experimental. They were added at Crypto++ 5.6.3. At compile time, it +// indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE) +// to select an implementation or "throw NotImplemented". At runtime, the +// class uses the result of CPUID to determine if RDRAND or RDSEED are +// 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. + +// 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 + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +// 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 + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +// 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 + +#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDRAND_ASM) +# define CRYPTOPP_BOOL_RDRAND_ASM 1 +#else +# define CRYPTOPP_BOOL_RDRAND_ASM 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 + +#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 0 +# 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 + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +#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 + +#if MASM_RDRAND_ASM_AVAILABLE +# ifdef _M_X64 +extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int); +// # pragma comment(lib, "rdrand-x64.lib") +# else +extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int); +// # pragma comment(lib, "rdrand-x86.lib") +# endif +#endif + +#if MASM_RDSEED_ASM_AVAILABLE +# ifdef _M_X64 +extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int); +// # pragma comment(lib, "rdrand-x64.lib") +# else +extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int); +// # pragma comment(lib, "rdrand-x86.lib") +# endif +#endif + +#if NASM_RDRAND_ASM_AVAILABLE +extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int); +#endif + +#if NASM_RDSEED_ASM_AVAILABLE +extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int); +#endif + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +#if ALL_RDRAND_INTRIN_AVAILABLE +static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety) +{ + assert((output && size) || !(output || size)); +#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32 + word64 val; +#else + word32 val; +#endif + + while (size >= sizeof(val)) + { +#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32 + if (_rdrand64_step((word64*)output)) +#else + if (_rdrand32_step((word32*)output)) +#endif + { + output += sizeof(val); + size -= sizeof(val); + } + else + { + if (!safety--) + return 0; + } + } + + if (size) + { +#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32 + if (_rdrand64_step(&val)) +#else + if (_rdrand32_step(&val)) +#endif + { + memcpy(output, &val, size); + size = 0; + } + else + { + if (!safety--) + return 0; + } + } + +#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32 + *((volatile word64*)&val) = 0; +#else + *((volatile word32*)&val) = 0; +#endif + + return int(size == 0); +} +#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 + word32 val; +#endif + char rc; + while (size) + { + __asm__ volatile( +#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; " + : "=a" (val), "=qm" (rc) + : + : "cc" + ); + + if (rc) + { + if (size >= sizeof(val)) + { +#if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) + *((word64*)output) = val; +#elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86) + *((word32*)output) = val; +#else + memcpy(output, &val, sizeof(val)); +#endif + output += sizeof(val); + size -= sizeof(val); + } + else + { + memcpy(output, &val, size); + size = 0; + } + } + else + { + if (!safety--) + break; + } + } + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + *((volatile word64*)&val) = 0; +#else + *((volatile word32*)&val) = 0; +#endif + + return int(size == 0); +} + +#endif // GCC_RDRAND_ASM_AVAILABLE + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +void RDRAND::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size); + assert((output && size) || !(output || size)); + + if(!HasRDRAND()) + throw NotImplemented("RDRAND: rdrand is not available on this platform"); + + int rc; CRYPTOPP_UNUSED(rc); +#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"); } +#else + // RDRAND not detected at compile time, and no suitable compiler found + throw NotImplemented("RDRAND: failed to find a suitable implementation???"); +#endif // CRYPTOPP_CPUID_AVAILABLE +} + +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(HasRDRAND()); +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + FixedSizeSecBlock<word64, 16> discard; + n = RoundUpToMultipleOf(n, sizeof(word64)); +#else + FixedSizeSecBlock<word32, 16> discard; + n = RoundUpToMultipleOf(n, sizeof(word32)); +#endif + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +#if ALL_RDSEED_INTRIN_AVAILABLE +static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety) +{ + assert((output && size) || !(output || size)); +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + word64 val; +#else + word32 val; +#endif + + while (size >= sizeof(val)) + { +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + if (_rdseed64_step((word64*)output)) +#else + if (_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 (_rdseed64_step(&val)) +#else + if (_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 + *((volatile word32*)&val) = 0; +#endif + + return int(size == 0); +} +#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 + word32 val; +#endif + char rc; + while (size) + { + __asm__ volatile( +#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; " + : "=a" (val), "=qm" (rc) + : + : "cc" + ); + + if (rc) + { + if (size >= sizeof(val)) + { +#if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) + *((word64*)output) = val; +#elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86) + *((word32*)output) = val; +#else + memcpy(output, &val, sizeof(val)); +#endif + output += sizeof(val); + size -= sizeof(val); + } + else + { + memcpy(output, &val, size); + size = 0; + } + } + else + { + if (!safety--) + break; + } + } + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + *((volatile word64*)&val) = 0; +#else + *((volatile word32*)&val) = 0; +#endif + + return int(size == 0); +} +#endif // GCC_RDSEED_ASM_AVAILABLE + +#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 && size) || !(output || size)); + + if(!HasRDSEED()) + throw NotImplemented("RDSEED: rdseed is not available on this platform"); + + int rc; CRYPTOPP_UNUSED(rc); +#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"); } +#else + // RDSEED not detected at compile time, and no suitable compiler found + throw NotImplemented("RDSEED: failed to find a suitable implementation???"); +#endif +} + +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(HasRDSEED()); +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 + FixedSizeSecBlock<word64, 16> discard; + n = RoundUpToMultipleOf(n, sizeof(word64)); +#else + FixedSizeSecBlock<word32, 16> discard; + n = RoundUpToMultipleOf(n, sizeof(word32)); +#endif + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +NAMESPACE_END |