Crypto++  8.2
Free C++ class library of cryptographic schemes
rdrand.cpp
1 // rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 
3 #include "pch.h"
4 #include "config.h"
5 #include "cryptlib.h"
6 #include "secblock.h"
7 #include "rdrand.h"
8 #include "cpu.h"
9 
10 // This file (and friends) provides both RDRAND and RDSEED. They were added
11 // at Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64}
12 // to select an implementation or throws "NotImplemented". Users of the
13 // classes should call HasRDRAND() or HasRDSEED() to determine if a
14 // generator is available at runtime.
15 // The original classes accepted a retry count. Retries were superflous for
16 // RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending
17 // on the processor. Retries were removed at Crypto++ 6.0 because
18 // GenerateBlock unconditionally retries and always fulfills the request.
19 // Intel recommends using a retry count in case RDRAND or RDSEED circuit
20 // is bad. This implemenation does not follow the advice and requires
21 // good silicon. If the circuit or processor is bad then the user has
22 // bigger problems than generating random numbers.
23 
24 /////////////////////////////////////////////////////////////////////
25 /////////////////////////////////////////////////////////////////////
26 
27 #if CRYPTOPP_MSC_VERSION
28 # pragma warning(disable: 4702)
29 #endif
30 
31 #if defined(CRYPTOPP_RDRAND_AVAILABLE)
32 # if defined(CRYPTOPP_MSC_VERSION)
33 # define MASM_RDRAND_ASM_AVAILABLE 1
34 # endif
35 # if (__SUNPRO_CC >= 0x5100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) || \
36  (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_GCC_VERSION >= 30200)
37 # define GCC_RDRAND_ASM_AVAILABLE 1
38 # endif
39 #endif // CRYPTOPP_RDRAND_AVAILABLE
40 
41 #if defined(CRYPTOPP_RDSEED_AVAILABLE)
42 # if defined(CRYPTOPP_MSC_VERSION)
43 # define MASM_RDSEED_ASM_AVAILABLE 1
44 # endif
45 # if (__SUNPRO_CC >= 0x5100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) || \
46  (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_GCC_VERSION >= 30200)
47 # define GCC_RDSEED_ASM_AVAILABLE 1
48 # endif
49 #endif // CRYPTOPP_RDSEED_AVAILABLE
50 
51 typedef unsigned char byte;
52 
53 #if MASM_RDRAND_ASM_AVAILABLE
54 extern "C" void CRYPTOPP_FASTCALL MASM_RDRAND_GenerateBlock(byte*, size_t);
55 #endif
56 
57 #if MASM_RDSEED_ASM_AVAILABLE
58 extern "C" void CRYPTOPP_FASTCALL MASM_RDSEED_GenerateBlock(byte*, size_t);
59 #endif
60 
61 /////////////////////////////////////////////////////////////////////
62 /////////////////////////////////////////////////////////////////////
63 
64 NAMESPACE_BEGIN(CryptoPP)
65 
66 #if defined(CRYPTOPP_RDRAND_AVAILABLE)
67 
68 // Fills 4 bytes
69 inline void RDRAND32(void* output)
70 {
71  CRYPTOPP_UNUSED(output); // MSC warning
72 #if defined(GCC_RDRAND_ASM_AVAILABLE)
73  __asm__ __volatile__
74  (
75  "1:\n"
76  ".byte 0x0f, 0xc7, 0xf0;\n"
77  "jnc 1b;\n"
78  : "=a" (*reinterpret_cast<word32*>(output))
79  : : "cc"
80  );
81 #endif
82 }
83 
84 #if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
85 // Fills 8 bytes
86 inline void RDRAND64(void* output)
87 {
88  CRYPTOPP_UNUSED(output); // MSC warning
89 #if defined(GCC_RDRAND_ASM_AVAILABLE)
90  __asm__ __volatile__
91  (
92  "1:\n"
93  ".byte 0x48, 0x0f, 0xc7, 0xf0;\n"
94  "jnc 1b;\n"
95  : "=a" (*reinterpret_cast<word64*>(output))
96  : : "cc"
97  );
98 #endif
99 }
100 #endif // RDRAND64
101 
103 {
104  if (!HasRDRAND())
105  throw RDRAND_Err("HasRDRAND");
106 }
107 
108 void RDRAND::GenerateBlock(byte *output, size_t size)
109 {
110  CRYPTOPP_ASSERT((output && size) || !(output || size));
111  if (size == 0) return;
112 
113 #if defined(MASM_RDRAND_ASM_AVAILABLE)
114 
115  MASM_RDRAND_GenerateBlock(output, size);
116 
117 #elif defined(GCC_RDRAND_ASM_AVAILABLE)
118 
119 # if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
120  size_t i = 0;
121  for (i = 0; i < size/8; i++)
122  RDRAND64(output+i*8);
123 
124  output += i*8;
125  size -= i*8;
126 
127  if (size)
128  {
129  word64 val;
130  RDRAND64(&val);
131  std::memcpy(output, &val, size);
132  }
133 # else
134  size_t i = 0;
135  for (i = 0; i < size/4; i++)
136  RDRAND32(output+i*4);
137 
138  output += i*4;
139  size -= i*4;
140 
141  if (size)
142  {
143  word32 val;
144  RDRAND32(&val);
145  std::memcpy(output, &val, size);
146  }
147 # endif
148 #else
149  // No suitable compiler found
150  CRYPTOPP_UNUSED(output);
151  throw NotImplemented("RDRAND: failed to find a suitable implementation");
152 #endif
153 }
154 
155 void RDRAND::DiscardBytes(size_t n)
156 {
157  // RoundUpToMultipleOf is used because a full word is read, and its cheaper
158  // to discard full words. There's no sense in dealing with tail bytes.
160  n = RoundUpToMultipleOf(n, sizeof(word64));
161 
162  size_t count = STDMIN(n, discard.SizeInBytes());
163  while (count)
164  {
165  GenerateBlock(discard.BytePtr(), count);
166  n -= count;
167  count = STDMIN(n, discard.SizeInBytes());
168  }
169 }
170 
171 #endif // CRYPTOPP_RDRAND_AVAILABLE
172 
173 /////////////////////////////////////////////////////////////////////
174 /////////////////////////////////////////////////////////////////////
175 
176 #if defined(CRYPTOPP_RDSEED_AVAILABLE)
177 
178 // Fills 4 bytes
179 inline void RDSEED32(void* output)
180 {
181  CRYPTOPP_UNUSED(output); // MSC warning
182 #if defined(GCC_RDSEED_ASM_AVAILABLE)
183  __asm__ __volatile__
184  (
185  "1:\n"
186  ".byte 0x0f, 0xc7, 0xf8;\n"
187  "jnc 1b;\n"
188  : "=a" (*reinterpret_cast<word32*>(output))
189  : : "cc"
190  );
191 #endif
192 }
193 
194 #if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
195 // Fills 8 bytes
196 inline void RDSEED64(void* output)
197 {
198  CRYPTOPP_UNUSED(output); // MSC warning
199 #if defined(GCC_RDSEED_ASM_AVAILABLE)
200  __asm__ __volatile__
201  (
202  "1:\n"
203  ".byte 0x48, 0x0f, 0xc7, 0xf8;\n"
204  "jnc 1b;\n"
205  : "=a" (*reinterpret_cast<word64*>(output))
206  : : "cc"
207  );
208 #endif
209 }
210 #endif // RDSEED64
211 
213 {
214  if (!HasRDSEED())
215  throw RDSEED_Err("HasRDSEED");
216 }
217 
218 void RDSEED::GenerateBlock(byte *output, size_t size)
219 {
220  CRYPTOPP_ASSERT((output && size) || !(output || size));
221  if (size == 0) return;
222 
223 #if defined(MASM_RDSEED_ASM_AVAILABLE)
224 
225  MASM_RDSEED_GenerateBlock(output, size);
226 
227 #elif defined(GCC_RDSEED_ASM_AVAILABLE)
228 # if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
229  size_t i = 0;
230  for (i = 0; i < size/8; i++)
231  RDSEED64(output+i*8);
232 
233  output += i*8;
234  size -= i*8;
235 
236  if (size)
237  {
238  word64 val;
239  RDSEED64(&val);
240  std::memcpy(output, &val, size);
241  }
242 # else
243  size_t i = 0;
244  for (i = 0; i < size/4; i++)
245  RDSEED32(output+i*4);
246 
247  output += i*4;
248  size -= i*4;
249 
250  if (size)
251  {
252  word32 val;
253  RDSEED32(&val);
254  std::memcpy(output, &val, size);
255  }
256 # endif
257 #else
258  // No suitable compiler found
259  CRYPTOPP_UNUSED(output);
260  throw NotImplemented("RDSEED: failed to find a suitable implementation");
261 #endif // RDSEED64
262 }
263 
264 void RDSEED::DiscardBytes(size_t n)
265 {
266  // RoundUpToMultipleOf is used because a full word is read, and its cheaper
267  // to discard full words. There's no sense in dealing with tail bytes.
269  n = RoundUpToMultipleOf(n, sizeof(word64));
270 
271  size_t count = STDMIN(n, discard.SizeInBytes());
272  while (count)
273  {
274  GenerateBlock(discard.BytePtr(), count);
275  n -= count;
276  count = STDMIN(n, discard.SizeInBytes());
277  }
278 }
279 
280 #else // not CRYPTOPP_CPUID_AVAILABLE
281 
283 {
284  throw RDRAND_Err("HasRDRAND");
285 }
286 
287 void RDRAND::GenerateBlock(byte *output, size_t size)
288 {
289  // Constructor will throw, should not get here
290  CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
291 }
292 
293 void RDRAND::DiscardBytes(size_t n)
294 {
295  // Constructor will throw, should not get here
296  CRYPTOPP_UNUSED(n);
297 }
298 
300 {
301  throw RDSEED_Err("HasRDSEED");
302 }
303 
304 void RDSEED::GenerateBlock(byte *output, size_t size)
305 {
306  // Constructor will throw, should not get here
307  CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
308 }
309 
310 void RDSEED::DiscardBytes(size_t n)
311 {
312  // Constructor will throw, should not get here
313  CRYPTOPP_UNUSED(n);
314 }
315 
316 #endif // CRYPTOPP_CPUID_AVAILABLE
317 
318 NAMESPACE_END
NotImplemented
A method was called which was not implemented.
Definition: cryptlib.h:232
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1151
rdrand.h
Classes for RDRAND and RDSEED.
RDRAND::RDRAND
RDRAND()
Construct a RDRAND generator.
Definition: rdrand.cpp:282
secblock.h
Classes and functions for secure memory allocations.
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
pch.h
Precompiled header file.
SecBlock< T, FixedSizeAllocatorWithCleanup< T, S > >::BytePtr
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:836
SecBlock< T, FixedSizeAllocatorWithCleanup< T, S > >::SizeInBytes
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:843
HasRDSEED
bool HasRDSEED()
Determine RDSEED availability.
Definition: cpu.h:305
RDRAND_Err
Exception thrown when a RDRAND generator encounters a generator related error.
Definition: rdrand.h:38
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:632
RDRAND::GenerateBlock
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:287
RDSEED::DiscardBytes
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.cpp:310
cpu.h
Functions for CPU features and intrinsics.
HasRDRAND
bool HasRDRAND()
Determine RDRAND availability.
Definition: cpu.h:290
RDSEED_Err
Exception thrown when a RDSEED generator encounters a generator related error.
Definition: rdrand.h:92
FixedSizeSecBlock
Fixed size stack-based SecBlock.
Definition: secblock.h:1110
RDSEED::GenerateBlock
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:304
CryptoPP
Crypto++ library namespace.
config.h
Library configuration file.
RDSEED::RDSEED
RDSEED()
Construct a RDSEED generator.
Definition: rdrand.cpp:299
cryptlib.h
Abstract base classes that provide a uniform interface to this library.
RDRAND::DiscardBytes
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.cpp:293