1 // rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 
3 /// \file rdrand.h
4 /// \brief Classes for RDRAND and RDSEED
5 /// \since Crypto++ 5.6.3
6 
7 #ifndef CRYPTOPP_RDRAND_H
8 #define CRYPTOPP_RDRAND_H
9 
10 #include "cryptlib.h"
11 
12 // This class file provides both RDRAND and RDSEED. They were added at
13 //   Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64}
14 //   to select an implementation or "throw NotImplemented". At runtime the
15 //   constructor will throw RDRAND_Err or RDSEED_Err if a generator is
16 //   is not available.
17 // The original classes accepted a retry count. Retries were superflous for
18 //   RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending
19 //   on the processor. Retries were removed at Crypto++ 6.0 because
20 //   GenerateBlock unconditionally retries and always fulfills the request.
21 
22 // Throughput varies wildly depending on processor and manufacturer. A Core i5 or
23 //   Core i7 RDRAND can generate at over 200 MiB/s. It is below theroetical
24 //   maximum, but it takes about 5 instructions to generate, retry and store a
25 //   result. A low-end Celeron may perform RDRAND at about 7 MiB/s. RDSEED
26 //   performs at about 1/4 to 1/2 the rate of RDRAND. AMD RDRAND performed poorly
27 //   during testing with Athlon X4 845. The Bulldozer v4 only performed at 1 MiB/s.
28 
29 // Microsoft added RDRAND in August 2012, VS2012; RDSEED in October 2013, VS2013.
30 // GCC added RDRAND in December 2010, GCC 4.6. LLVM added RDRAND in July 2012,
31 // Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1.
32 
NAMESPACE_BEGIN(CryptoPP)33 NAMESPACE_BEGIN(CryptoPP)
34 
35 /// \brief Exception thrown when a RDRAND generator encounters
36 ///    a generator related error.
37 /// \since Crypto++ 5.6.3
38 class RDRAND_Err : public Exception
39 {
40 public:
41     RDRAND_Err(const std::string &operation)
42         : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {}
43 };
44 
45 /// \brief Hardware generated random numbers using RDRAND instruction
46 /// \sa MaurerRandomnessTest() for random bit generators
47 /// \since Crypto++ 5.6.3
48 class RDRAND : public RandomNumberGenerator
49 {
50 public:
StaticAlgorithmName()51     CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDRAND"; }
52 
~RDRAND()53     virtual ~RDRAND() {}
54 
55     /// \brief Construct a RDRAND generator
56     /// \details According to DJ of Intel, the Intel RDRAND circuit does not underflow.
57     ///   If it did hypothetically underflow, then it would return 0 for the random value.
58     ///   AMD's RDRAND implementation appears to provide the same behavior.
59      /// \throw RDRAND_Err if the random number generator is not available
60     RDRAND();
61 
62     /// \brief Generate random array of bytes
63     /// \param output the byte buffer
64     /// \param size the length of the buffer, in bytes
65     virtual void GenerateBlock(byte *output, size_t size);
66 
67     /// \brief Generate and discard n bytes
68     /// \param n the number of bytes to generate and discard
69     /// \details the RDSEED generator discards words, not bytes. If n is
70     ///   not a multiple of a machine word, then it is rounded up to
71     ///   that size.
72     virtual void DiscardBytes(size_t n);
73 
74     /// \brief Update RNG state with additional unpredictable values
75     /// \param input unused
76     /// \param length unused
77     /// \details The operation is a nop for this generator.
IncorporateEntropy(const byte * input,size_t length)78     virtual void IncorporateEntropy(const byte *input, size_t length)
79     {
80         // Override to avoid the base class' throw.
81         CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
82     }
83 
AlgorithmProvider()84     std::string AlgorithmProvider() const {
85         return "RDRAND";
86     }
87 };
88 
89 /// \brief Exception thrown when a RDSEED generator encounters
90 ///    a generator related error.
91 /// \since Crypto++ 5.6.3
92 class RDSEED_Err : public Exception
93 {
94 public:
RDSEED_Err(const std::string & operation)95     RDSEED_Err(const std::string &operation)
96         : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {}
97 };
98 
99 /// \brief Hardware generated random numbers using RDSEED instruction
100 /// \sa MaurerRandomnessTest() for random bit generators
101 /// \since Crypto++ 5.6.3
102 class RDSEED : public RandomNumberGenerator
103 {
104 public:
StaticAlgorithmName()105     CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDSEED"; }
106 
~RDSEED()107     virtual ~RDSEED() {}
108 
109     /// \brief Construct a RDSEED generator
110     /// \details Empirical testing under a 6th generaton i7 (6200U) shows RDSEED fails
111     ///   to fulfill requests at about once every for every 256 bytes requested.
112     ///   The generator runs about 4 times slower than RDRAND.
113      /// \throw RDSEED_Err if the random number generator is not available
114     RDSEED();
115 
116     /// \brief Generate random array of bytes
117     /// \param output the byte buffer
118     /// \param size the length of the buffer, in bytes
119     virtual void GenerateBlock(byte *output, size_t size);
120 
121     /// \brief Generate and discard n bytes
122     /// \param n the number of bytes to generate and discard
123     /// \details the RDSEED generator discards words, not bytes. If n is
124     ///   not a multiple of a machine word, then it is rounded up to
125     ///   that size.
126     virtual void DiscardBytes(size_t n);
127 
128     /// \brief Update RNG state with additional unpredictable values
129     /// \param input unused
130     /// \param length unused
131     /// \details The operation is a nop for this generator.
IncorporateEntropy(const byte * input,size_t length)132     virtual void IncorporateEntropy(const byte *input, size_t length)
133     {
134         // Override to avoid the base class' throw.
135         CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
136     }
137 
AlgorithmProvider()138     std::string AlgorithmProvider() const {
139         return "RDSEED";
140     }
141 };
142 
143 NAMESPACE_END
144 
145 #endif // CRYPTOPP_RDRAND_H
146