Security Scol plugin
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 superfluous 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 implementation 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
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
51typedef unsigned char byte;
52
53#if MASM_RDRAND_ASM_AVAILABLE
54extern "C" void CRYPTOPP_FASTCALL MASM_RDRAND_GenerateBlock(byte*, size_t);
55#endif
56
57#if MASM_RDSEED_ASM_AVAILABLE
58extern "C" void CRYPTOPP_FASTCALL MASM_RDSEED_GenerateBlock(byte*, size_t);
59#endif
60
63
64NAMESPACE_BEGIN(CryptoPP)
65
66#if defined(CRYPTOPP_RDRAND_AVAILABLE)
67
68// Fills 4 bytes
69inline 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
86inline 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
108void 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
155void 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
175
176#if defined(CRYPTOPP_RDSEED_AVAILABLE)
177
178// Fills 4 bytes
179inline 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
196inline 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
218void 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
264void 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
284
285#if !defined(CRYPTOPP_RDRAND_AVAILABLE)
286
288{
289 throw RDRAND_Err("HasRDRAND");
290}
291
292void 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
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
313void 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
320{
321 // Constructor will throw, should not get here
322 CRYPTOPP_UNUSED(n);
323}
324
325#endif // CRYPTOPP_RDSEED_AVAILABLE
326
327NAMESPACE_END
Fixed size stack-based SecBlock.
Definition secblock.h:1246
A method was called which was not implemented.
Definition cryptlib.h:233
Exception thrown when a RDRAND generator encounters a generator related error.
Definition rdrand.h:39
RDRAND()
Construct a RDRAND generator.
Definition rdrand.cpp:287
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition rdrand.cpp:292
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition rdrand.cpp:298
Exception thrown when a RDSEED generator encounters a generator related error.
Definition rdrand.h:93
RDSEED()
Construct a RDSEED generator.
Definition rdrand.cpp:308
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition rdrand.cpp:313
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition rdrand.cpp:319
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition secblock.h:885
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition secblock.h:876
Library configuration file.
unsigned char byte
8-bit unsigned datatype
Definition config_int.h:56
unsigned int word32
32-bit unsigned datatype
Definition config_int.h:62
Functions for CPU features and intrinsics.
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:1175
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition misc.h:655
Precompiled header file.
Classes for RDRAND and RDSEED.
Classes and functions for secure memory allocations.