Botan 3.8.1
Crypto and TLS for C&
rdseed.cpp
Go to the documentation of this file.
1/*
2* Entropy Source Using Intel's rdseed instruction
3* (C) 2015 Daniel Neus
4* (C) 2015,2019 Jack Lloyd
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/rdseed.h>
10
11#include <botan/compiler.h>
12#include <botan/rng.h>
13#include <botan/internal/cpuid.h>
14#include <botan/internal/target_info.h>
15
16#if !defined(BOTAN_USE_GCC_INLINE_ASM)
17 #include <immintrin.h>
18#endif
19
20namespace Botan {
21
22namespace {
23
24BOTAN_FUNC_ISA("rdseed") bool read_rdseed(secure_vector<uint32_t>& seed) {
25 /*
26 * RDSEED is not guaranteed to generate an output within any specific number
27 * of attempts. However in testing on a Skylake system, with all hyperthreads
28 * occupied in tight RDSEED loops, RDSEED will still usually succeed in under
29 * 150 attempts. The maximum ever seen was 230 attempts until success. When
30 * idle, RDSEED usually succeeds in 1 or 2 attempts.
31 *
32 * We set an upper bound of 1024 attempts, because it is possible that due
33 * to firmware issue RDSEED is simply broken and never succeeds. We do not
34 * want to loop forever in that case. If we exceed that limit, then we assume
35 * the hardware is actually just broken, and stop the poll.
36 */
37 const size_t RDSEED_RETRIES = 1024;
38
39 for(size_t i = 0; i != RDSEED_RETRIES; ++i) {
40 uint32_t r = 0;
41 int cf = 0;
42
43#if defined(BOTAN_USE_GCC_INLINE_ASM)
44 asm("rdseed %0; adcl $0,%1" : "=r"(r), "=r"(cf) : "0"(r), "1"(cf) : "cc");
45#else
46 cf = _rdseed32_step(&r);
47#endif
48
49 if(1 == cf) {
50 seed.push_back(r);
51 return true;
52 }
53
54 // Intel suggests pausing if RDSEED fails.
55#if defined(BOTAN_USE_GCC_INLINE_ASM)
56 asm volatile("pause");
57#else
58 _mm_pause();
59#endif
60 }
61
62 return false; // failed to produce an output after many attempts
63}
64
65} // namespace
66
68 const size_t RDSEED_BYTES = 1024;
69 static_assert(RDSEED_BYTES % 4 == 0, "Bad RDSEED configuration");
70
73 seed.reserve(RDSEED_BYTES / 4);
74
75 for(size_t p = 0; p != RDSEED_BYTES / 4; ++p) {
76 /*
77 If at any point we exceed our retry count, we stop the entire seed
78 gathering process. This situation will only occur in situations of
79 extremely high RDSEED utilization. If RDSEED is currently so highly
80 contended, then the rest of the poll is likely to also face contention and
81 it is better to quit now rather than (presumably) face very high retry
82 times for the rest of the poll.
83 */
84 if(!read_rdseed(seed)) {
85 break;
86 }
87 }
88
89 if(!seed.empty()) {
90 rng.add_entropy(reinterpret_cast<const uint8_t*>(seed.data()), seed.size() * sizeof(uint32_t));
91 }
92 }
93
94 // RDSEED is used but not trusted
95 return 0;
96}
97
98} // namespace Botan
static bool has(CPUID::Feature feat)
Definition cpuid.h:94
size_t poll(RandomNumberGenerator &rng) override
Definition rdseed.cpp:67
void add_entropy(std::span< const uint8_t > input)
Definition rng.h:91
#define BOTAN_FUNC_ISA(isa)
Definition compiler.h:54
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:65