Crypto++  8.6
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 #endif // CRYPTOPP_RDSEED_AVAILABLE
281 
282 /////////////////////////////////////////////////////////////////////
283 /////////////////////////////////////////////////////////////////////
284 
285 #if !defined(CRYPTOPP_RDRAND_AVAILABLE)
286 
288 {
289  throw RDRAND_Err("HasRDRAND");
290 }
291 
292 void RDRAND::GenerateBlock(byte *output, size_t size)
293 {
294  // Constructor will throw, should not get here
295  CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
296 }
297 
298 void RDRAND::DiscardBytes(size_t n)
299 {
300  // Constructor will throw, should not get here
301  CRYPTOPP_UNUSED(n);
302 }
303 
304 #endif // CRYPTOPP_RDRAND_AVAILABLE
305 
306 #if !defined(CRYPTOPP_RDSEED_AVAILABLE)
307 
309 {
310  throw RDSEED_Err("HasRDSEED");
311 }
312 
313 void RDSEED::GenerateBlock(byte *output, size_t size)
314 {
315  // Constructor will throw, should not get here
316  CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
317 }
318 
319 void RDSEED::DiscardBytes(size_t n)
320 {
321  // Constructor will throw, should not get here
322  CRYPTOPP_UNUSED(n);
323 }
324 
325 #endif // CRYPTOPP_RDSEED_AVAILABLE
326 
327 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:1174
byte
unsigned char byte
8-bit unsigned datatype
Definition: config_int.h:56
rdrand.h
Classes for RDRAND and RDSEED.
RDRAND::RDRAND
RDRAND()
Construct a RDRAND generator.
Definition: rdrand.cpp:287
secblock.h
Classes and functions for secure memory allocations.
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68
word64
unsigned long long word64
64-bit unsigned datatype
Definition: config_int.h:91
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:876
word32
unsigned int word32
32-bit unsigned datatype
Definition: config_int.h:62
SecBlock< T, FixedSizeAllocatorWithCleanup< T, S > >::SizeInBytes
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:885
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:655
RDRAND::GenerateBlock
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:292
RDSEED::DiscardBytes
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.cpp:319
cpu.h
Functions for CPU features and intrinsics.
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:1245
RDSEED::GenerateBlock
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:313
CryptoPP
Crypto++ library namespace.
config.h
Library configuration file.
RDSEED::RDSEED
RDSEED()
Construct a RDSEED generator.
Definition: rdrand.cpp:308
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:298