00001 // rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. 00002 // Copyright assigned to Crypto++ project. 00003 00004 //! \file 00005 //! \headerfile rdrand.h 00006 //! \brief Classes for RDRAND and RDSEED 00007 00008 #ifndef CRYPTOPP_RDRAND_H 00009 #define CRYPTOPP_RDRAND_H 00010 00011 #include "cryptlib.h" 00012 00013 // This file (and friends) provides both RDRAND and RDSEED, but its somewhat 00014 // experimental. They were added at Crypto++ 5.6.3. At compile time, it 00015 // indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE) 00016 // to select an implementation or "throw NotImplemented". At runtime, the 00017 // class uses the result of CPUID to determine if RDRAND or RDSEED are 00018 // available. A lazy throw strategy is used in case the CPU does not support 00019 // the instruction. I.e., the throw is deferred until GenerateBlock() is called. 00020 00021 // Microsoft added RDRAND in August 2012, VS2012. GCC added RDRAND in December 2010, GCC 4.6. 00022 // Clang added RDRAND in July 2012, Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1. 00023 00024 NAMESPACE_BEGIN(CryptoPP) 00025 00026 //! \brief Exception thrown when a RDRAND generator encounters 00027 //! a generator related error. 00028 class RDRAND_Err : public Exception 00029 { 00030 public: 00031 RDRAND_Err(const std::string &operation) 00032 : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {} 00033 }; 00034 00035 //! \brief Hardware generated random numbers using RDRAND instruction 00036 //! \sa MaurerRandomnessTest() for random bit generators 00037 class RDRAND : public RandomNumberGenerator 00038 { 00039 public: 00040 std::string AlgorithmName() const {return "RDRAND";} 00041 00042 //! \brief Construct a RDRAND generator 00043 //! \param retries the number of retries for failed calls to the hardware 00044 //! \details RDRAND() constructs a generator with a maximum number of retires 00045 //! for failed generation attempts. 00046 RDRAND(unsigned int retries = 8) : m_retries(retries) {} 00047 00048 virtual ~RDRAND() {} 00049 00050 //! \brief Retrieve the number of retries used by the generator 00051 //! \returns the number of times GenerateBlock() will attempt to recover from a failed generation 00052 unsigned int GetRetries() const 00053 { 00054 return m_retries; 00055 } 00056 00057 //! \brief Set the number of retries used by the generator 00058 //! \param retries number of times GenerateBlock() will attempt to recover from a failed generation 00059 void SetRetries(unsigned int retries) 00060 { 00061 m_retries = retries; 00062 } 00063 00064 //! \brief Generate random array of bytes 00065 //! \param output the byte buffer 00066 //! \param size the length of the buffer, in bytes 00067 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) 00068 virtual void GenerateBlock(byte *output, size_t size); 00069 #else 00070 virtual void GenerateBlock(byte *output, size_t size) { 00071 CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size); 00072 throw NotImplemented("RDRAND: rdrand is not available on this platform"); 00073 } 00074 #endif 00075 00076 //! \brief Generate and discard n bytes 00077 //! \param n the number of bytes to generate and discard 00078 //! \details the RDSEED generator discards words, not bytes. If n is 00079 //! not a multiple of a machine word, then it is rounded up to 00080 //! that size. 00081 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) 00082 virtual void DiscardBytes(size_t n); 00083 #else 00084 virtual void DiscardBytes(size_t n) { 00085 CRYPTOPP_UNUSED(n); 00086 throw NotImplemented("RDRAND: rdrand is not available on this platform"); 00087 } 00088 #endif 00089 00090 //! Update RNG state with additional unpredictable values 00091 //! \param input unused 00092 //! \param length unused 00093 //! \details The operation is a nop for this generator. 00094 virtual void IncorporateEntropy(const byte *input, size_t length) 00095 { 00096 // Override to avoid the base class' throw. 00097 CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); 00098 assert(0); // warn in debug builds 00099 } 00100 00101 private: 00102 unsigned int m_retries; 00103 }; 00104 00105 //! \brief Exception thrown when a RDSEED generator encounters 00106 //! a generator related error. 00107 class RDSEED_Err : public Exception 00108 { 00109 public: 00110 RDSEED_Err(const std::string &operation) 00111 : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {} 00112 }; 00113 00114 //! \brief Hardware generated random numbers using RDSEED instruction 00115 //! \sa MaurerRandomnessTest() for random bit generators 00116 class RDSEED : public RandomNumberGenerator 00117 { 00118 public: 00119 std::string AlgorithmName() const {return "RDSEED";} 00120 00121 //! \brief Construct a RDSEED generator 00122 //! \param retries the number of retries for failed calls to the hardware 00123 //! \details RDSEED() constructs a generator with a maximum number of retires 00124 //! for failed generation attempts. 00125 RDSEED(unsigned int retries = 8) : m_retries(retries) {} 00126 00127 virtual ~RDSEED() {} 00128 00129 //! \brief Retrieve the number of retries used by the generator 00130 //! \returns the number of times GenerateBlock() will attempt to recover from a failed generation 00131 unsigned int GetRetries() const 00132 { 00133 return m_retries; 00134 } 00135 00136 //! \brief Set the number of retries used by the generator 00137 //! \param retries number of times GenerateBlock() will attempt to recover from a failed generation 00138 void SetRetries(unsigned int retries) 00139 { 00140 m_retries = retries; 00141 } 00142 00143 //! \brief Generate random array of bytes 00144 //! \param output the byte buffer 00145 //! \param size the length of the buffer, in bytes 00146 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) 00147 virtual void GenerateBlock(byte *output, size_t size); 00148 #else 00149 virtual void GenerateBlock(byte *output, size_t size) { 00150 CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size); 00151 throw NotImplemented("RDSEED: rdseed is not available on this platform"); 00152 } 00153 #endif 00154 00155 //! \brief Generate and discard n bytes 00156 //! \param n the number of bytes to generate and discard 00157 //! \details the RDSEED generator discards words, not bytes. If n is 00158 //! not a multiple of a machine word, then it is rounded up to 00159 //! that size. 00160 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) 00161 virtual void DiscardBytes(size_t n); 00162 #else 00163 virtual void DiscardBytes(size_t n) { 00164 CRYPTOPP_UNUSED(n); 00165 throw NotImplemented("RDSEED: rdseed is not available on this platform"); 00166 } 00167 #endif 00168 00169 //! Update RNG state with additional unpredictable values 00170 //! \param input unused 00171 //! \param length unused 00172 //! \details The operation is a nop for this generator. 00173 virtual void IncorporateEntropy(const byte *input, size_t length) 00174 { 00175 // Override to avoid the base class' throw. 00176 CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); 00177 assert(0); // warn in debug builds 00178 } 00179 00180 private: 00181 unsigned int m_retries; 00182 }; 00183 00184 NAMESPACE_END 00185 00186 #endif // CRYPTOPP_RDRAND_H