summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp')
-rw-r--r--comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp
new file mode 100644
index 0000000000..1830edf9de
--- /dev/null
+++ b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp
@@ -0,0 +1,97 @@
+/*
+* Entropy Source Using Intel's rdseed instruction
+* (C) 2015 Daniel Neus
+* (C) 2015,2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/rdseed.h>
+#include <botan/cpuid.h>
+
+#include <immintrin.h>
+
+namespace Botan {
+
+namespace {
+
+BOTAN_FUNC_ISA("rdseed")
+bool read_rdseed(secure_vector<uint32_t>& seed)
+ {
+ /*
+ * RDSEED is not guaranteed to generate an output within any specific number
+ * of attempts. However in testing on a Skylake system, with all hyperthreads
+ * occupied in tight RDSEED loops, RDSEED will still usually succeed in under
+ * 150 attempts. The maximum ever seen was 230 attempts until success. When
+ * idle, RDSEED usually succeeds in 1 or 2 attempts.
+ *
+ * We set an upper bound of 512 attempts, because it is possible that due
+ * to firmware issue RDSEED is simply broken and never succeeds. We do not
+ * want to loop forever in that case. If we exceed that limit, then we assume
+ * the hardware is actually just broken, and stop the poll.
+ */
+ const size_t RDSEED_RETRIES = 512;
+
+ for(size_t i = 0; i != RDSEED_RETRIES; ++i)
+ {
+ uint32_t r = 0;
+ int cf = 0;
+
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+ asm("rdseed %0; adcl $0,%1" :
+ "=r" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+#else
+ cf = _rdseed32_step(&r);
+#endif
+
+ if(1 == cf)
+ {
+ seed.push_back(r);
+ return true;
+ }
+
+ // Intel suggests pausing if RDSEED fails.
+ _mm_pause();
+ }
+
+ return false; // failed to produce an output after many attempts
+ }
+
+}
+
+size_t Intel_Rdseed::poll(RandomNumberGenerator& rng)
+ {
+ const size_t RDSEED_BYTES = 1024;
+ static_assert(RDSEED_BYTES % 4 == 0, "Bad RDSEED configuration");
+
+ if(CPUID::has_rdseed())
+ {
+ secure_vector<uint32_t> seed;
+ seed.reserve(RDSEED_BYTES / 4);
+
+ for(size_t p = 0; p != RDSEED_BYTES / 4; ++p)
+ {
+ /*
+ If at any point we exceed our retry count, we stop the entire seed
+ gathering process. This situation will only occur in situations of
+ extremely high RDSEED utilization. If RDSEED is currently so highly
+ contended, then the rest of the poll is likely to also face contention and
+ it is better to quit now rather than (presumably) face very high retry
+ times for the rest of the poll.
+ */
+ if(!read_rdseed(seed))
+ break;
+ }
+
+ if(seed.size() > 0)
+ {
+ rng.add_entropy(reinterpret_cast<const uint8_t*>(seed.data()),
+ seed.size() * sizeof(uint32_t));
+ }
+ }
+
+ // RDSEED is used but not trusted
+ return 0;
+ }
+
+}