diff options
Diffstat (limited to 'src/lib/rng/rdrand_rng')
-rw-r--r-- | src/lib/rng/rdrand_rng/info.txt | 16 | ||||
-rw-r--r-- | src/lib/rng/rdrand_rng/rdrand_rng.cpp | 84 | ||||
-rw-r--r-- | src/lib/rng/rdrand_rng/rdrand_rng.h | 60 |
3 files changed, 160 insertions, 0 deletions
diff --git a/src/lib/rng/rdrand_rng/info.txt b/src/lib/rng/rdrand_rng/info.txt new file mode 100644 index 000000000..2e597ebec --- /dev/null +++ b/src/lib/rng/rdrand_rng/info.txt @@ -0,0 +1,16 @@ +define RDRAND_RNG 20160619 + +need_isa rdrand + +<arch> +x86_32 +x86_64 +</arch> + +<cc> +gcc +clang +icc +msvc +</cc> + diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/lib/rng/rdrand_rng/rdrand_rng.cpp new file mode 100644 index 000000000..4d2e51cf8 --- /dev/null +++ b/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -0,0 +1,84 @@ +/** +* RDRAND RNG +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rdrand_rng.h> +#include <botan/loadstor.h> +#include <botan/cpuid.h> + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #include <immintrin.h> +#endif + +namespace Botan { + +RDRAND_RNG::RDRAND_RNG() + { + if(!CPUID::has_rdrand()) + throw Exception("Current CPU does not support RDRAND instruction"); + } + +//static +uint32_t RDRAND_RNG::rdrand() + { + bool ok = false; + uint32_t r = rdrand_status(ok); + + while(!ok) + { + r = rdrand_status(ok); + } + + return r; + } + +//static +uint32_t RDRAND_RNG::rdrand_status(bool& ok) + { + ok = false; + uint32_t r = 0; + + for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i) + { +#if defined(BOTAN_USE_GCC_INLINE_ASM) + int cf = 0; + + // Encoding of rdrand %eax + asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" : + "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + int cf = _rdrand32_step(&r); +#endif + if(1 == cf) + { + ok = true; + return r; + } + } + + return 0; + } + +void RDRAND_RNG::randomize(uint8_t out[], size_t out_len) + { + while(out_len >= 4) + { + uint32_t r = RDRAND_RNG::rdrand(); + + store_le(r, out); + out += 4; + out_len -= 4; + } + + if(out_len) // between 1 and 3 trailing bytes + { + uint32_t r = RDRAND_RNG::rdrand(); + for(size_t i = 0; i != out_len; ++i) + out[i] = get_byte(i, r); + } + } + +} diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/lib/rng/rdrand_rng/rdrand_rng.h new file mode 100644 index 000000000..fcd54035b --- /dev/null +++ b/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -0,0 +1,60 @@ +/** +* RDRAND RNG +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RNG_RDRAND_H__ +#define BOTAN_RNG_RDRAND_H__ + +#include <botan/rng.h> + +namespace Botan { + +class BOTAN_DLL RDRAND_RNG : public Hardware_RNG + { + public: + /** + * On correctly working hardware, RDRAND is always supposed to + * succeed within a set number of retries. If after that many + * retries RDRAND has still not suceeded, sets ok = false and + * returns 0. + */ + static uint32_t rdrand_status(bool& ok); + + /* + * Calls RDRAND until it succeeds, this could hypothetically + * loop forever on broken hardware. + */ + static uint32_t rdrand(); + + /** + * Constructor will throw if CPU does not have RDRAND bit set + */ + RDRAND_RNG(); + + /** + * Uses RDRAND to produce output + */ + void randomize(uint8_t out[], size_t out_len) override; + + /* + * No way to provide entropy to RDRAND generator, so add_entropy is ignored + */ + void add_entropy(const uint8_t[], size_t) override + { /* no op */ } + + size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override + { return 0; /* no op */ } + + std::string name() const override { return "RDRAND"; } + + bool is_seeded() const override { return true; } + + void clear() override {} + }; + +} + +#endif |