Crypto++ 8.2
Free C&
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 defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
28
29# if defined(CRYPTOPP_MSC_VERSION)
30# define MASM_RDRAND_ASM_AVAILABLE 1
31# define MASM_RDSEED_ASM_AVAILABLE 1
32# endif
33
34# if (__SUNPRO_CC >= 0x5100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) || \
35 (CRYPTOPP_CLANG_VERSION >= 20800) || (CRYPTOPP_GCC_VERSION >= 30200)
36# define GCC_RDRAND_ASM_AVAILABLE 1
37# define GCC_RDSEED_ASM_AVAILABLE 1
38# endif
39
40#endif // CRYPTOPP_CPUID_AVAILABLE
41
42typedef unsigned char byte;
43
44#if MASM_RDRAND_ASM_AVAILABLE
45extern "C" void CRYPTOPP_FASTCALL MASM_RDRAND_GenerateBlock(byte*, size_t);
46#endif
47
48#if MASM_RDSEED_ASM_AVAILABLE
49extern "C" void CRYPTOPP_FASTCALL MASM_RDSEED_GenerateBlock(byte*, size_t);
50#endif
51
52/////////////////////////////////////////////////////////////////////
53/////////////////////////////////////////////////////////////////////
54
55NAMESPACE_BEGIN(CryptoPP)
56
57#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
58
59// Fills 4 bytes
60inline void RDRAND32(void* output)
61{
62 CRYPTOPP_UNUSED(output); // MSC warning
63#if defined(GCC_RDRAND_ASM_AVAILABLE)
64 __asm__ __volatile__
65 (
66 "1:\n"
67 ".byte 0x0f, 0xc7, 0xf0;\n"
68 "jnc 1b;\n"
69 : "=a" (*reinterpret_cast<word32*>(output))
70 : : "cc"
71 );
72#endif
73}
74
75#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
76// Fills 8 bytes
77inline void RDRAND64(void* output)
78{
79 CRYPTOPP_UNUSED(output); // MSC warning
80#if defined(GCC_RDRAND_ASM_AVAILABLE)
81 __asm__ __volatile__
82 (
83 "1:\n"
84 ".byte 0x48, 0x0f, 0xc7, 0xf0;\n"
85 "jnc 1b;\n"
86 : "=a" (*reinterpret_cast<word64*>(output))
87 : : "cc"
88 );
89#endif
90}
91#endif // RDRAND64
92
94{
95 if (!HasRDRAND())
96 throw RDRAND_Err("HasRDRAND");
97}
98
99void RDRAND::GenerateBlock(byte *output, size_t size)
100{
101 CRYPTOPP_ASSERT((output && size) || !(output || size));
102 if (size == 0) return;
103
104#if defined(MASM_RDRAND_ASM_AVAILABLE)
105
106 MASM_RDRAND_GenerateBlock(output, size);
107
108#elif defined(GCC_RDRAND_ASM_AVAILABLE)
109
110# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
111 size_t i = 0;
112 for (i = 0; i < size/8; i++)
113 RDRAND64(output+i*8);
114
115 output += i*8;
116 size -= i*8;
117
118 if (size)
119 {
120 word64 val;
121 RDRAND64(&val);
122 std::memcpy(output, &val, size);
123 }
124# else
125 size_t i = 0;
126 for (i = 0; i < size/4; i++)
127 RDRAND32(output+i*4);
128
129 output += i*4;
130 size -= i*4;
131
132 if (size)
133 {
134 word32 val;
135 RDRAND32(&val);
136 std::memcpy(output, &val, size);
137 }
138# endif
139#else
140 // No suitable compiler found
141 CRYPTOPP_UNUSED(output);
142 throw NotImplemented("RDRAND: failed to find a suitable implementation");
143#endif
144}
145
147{
148 // RoundUpToMultipleOf is used because a full word is read, and its cheaper
149 // to discard full words. There's no sense in dealing with tail bytes.
151 n = RoundUpToMultipleOf(n, sizeof(word64));
152
153 size_t count = STDMIN(n, discard.SizeInBytes());
154 while (count)
155 {
156 GenerateBlock(discard.BytePtr(), count);
157 n -= count;
158 count = STDMIN(n, discard.SizeInBytes());
159 }
160}
161
162/////////////////////////////////////////////////////////////////////
163/////////////////////////////////////////////////////////////////////
164
165// Fills 4 bytes
166inline void RDSEED32(void* output)
167{
168 CRYPTOPP_UNUSED(output); // MSC warning
169#if defined(GCC_RDSEED_ASM_AVAILABLE)
170 __asm__ __volatile__
171 (
172 "1:\n"
173 ".byte 0x0f, 0xc7, 0xf8;\n"
174 "jnc 1b;\n"
175 : "=a" (*reinterpret_cast<word32*>(output))
176 : : "cc"
177 );
178#endif
179}
180
181#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
182// Fills 8 bytes
183inline void RDSEED64(void* output)
184{
185 CRYPTOPP_UNUSED(output); // MSC warning
186#if defined(GCC_RDSEED_ASM_AVAILABLE)
187 __asm__ __volatile__
188 (
189 "1:\n"
190 ".byte 0x48, 0x0f, 0xc7, 0xf8;\n"
191 "jnc 1b;\n"
192 : "=a" (*reinterpret_cast<word64*>(output))
193 : : "cc"
194 );
195#endif
196}
197#endif // RDSEED64
198
200{
201 if (!HasRDSEED())
202 throw RDSEED_Err("HasRDSEED");
203}
204
205void RDSEED::GenerateBlock(byte *output, size_t size)
206{
207 CRYPTOPP_ASSERT((output && size) || !(output || size));
208 if (size == 0) return;
209
210#if defined(MASM_RDSEED_ASM_AVAILABLE)
211
212 MASM_RDSEED_GenerateBlock(output, size);
213
214#elif defined(GCC_RDSEED_ASM_AVAILABLE)
215# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
216 size_t i = 0;
217 for (i = 0; i < size/8; i++)
218 RDSEED64(output+i*8);
219
220 output += i*8;
221 size -= i*8;
222
223 if (size)
224 {
225 word64 val;
226 RDSEED64(&val);
227 std::memcpy(output, &val, size);
228 }
229# else
230 size_t i = 0;
231 for (i = 0; i < size/4; i++)
232 RDSEED32(output+i*4);
233
234 output += i*4;
235 size -= i*4;
236
237 if (size)
238 {
239 word32 val;
240 RDSEED32(&val);
241 std::memcpy(output, &val, size);
242 }
243# endif
244#else
245 // No suitable compiler found
246 CRYPTOPP_UNUSED(output);
247 throw NotImplemented("RDSEED: failed to find a suitable implementation");
248#endif // RDSEED64
249}
250
252{
253 // RoundUpToMultipleOf is used because a full word is read, and its cheaper
254 // to discard full words. There's no sense in dealing with tail bytes.
256 n = RoundUpToMultipleOf(n, sizeof(word64));
257
258 size_t count = STDMIN(n, discard.SizeInBytes());
259 while (count)
260 {
261 GenerateBlock(discard.BytePtr(), count);
262 n -= count;
263 count = STDMIN(n, discard.SizeInBytes());
264 }
265}
266
267#else // not CRYPTOPP_CPUID_AVAILABLE
268
270{
271 throw RDRAND_Err("HasRDRAND");
272}
273
274void RDRAND::GenerateBlock(byte *output, size_t size)
275{
276 // Constructor will throw, should not get here
277 CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
278}
279
280void RDRAND::DiscardBytes(size_t n)
281{
282 // Constructor will throw, should not get here
283 CRYPTOPP_UNUSED(n);
284}
285
287{
288 throw RDSEED_Err("HasRDSEED");
289}
290
291void RDSEED::GenerateBlock(byte *output, size_t size)
292{
293 // Constructor will throw, should not get here
294 CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
295}
296
297void RDSEED::DiscardBytes(size_t n)
298{
299 // Constructor will throw, should not get here
300 CRYPTOPP_UNUSED(n);
301}
302
303#endif // CRYPTOPP_CPUID_AVAILABLE
304
305NAMESPACE_END
Fixed size stack-based SecBlock.
Definition: secblock.h:1078
A method was called which was not implemented.
Definition: cryptlib.h:224
Exception thrown when a RDRAND generator encounters a generator related error.
Definition: rdrand.h:39
RDRAND()
Construct a RDRAND generator.
Definition: rdrand.cpp:93
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:99
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.cpp:146
Exception thrown when a RDSEED generator encounters a generator related error.
Definition: rdrand.h:93
RDSEED()
Construct a RDSEED generator.
Definition: rdrand.cpp:199
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.cpp:205
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.cpp:251
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:811
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:804
Library configuration file.
Functions for CPU features and intrinsics.
bool HasRDRAND()
Determines RDRAND availability.
Definition: cpu.h:247
bool HasRDSEED()
Determines RDSEED availability.
Definition: cpu.h:258
Abstract base classes that provide a uniform interface to this library.
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1085
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:567
Crypto++ library namespace.
Precompiled header file.
Classes for RDRAND and RDSEED.
Classes and functions for secure memory allocations.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69