diff options
-rw-r--r-- | src/build-data/policy/bsi.txt | 1 | ||||
-rw-r--r-- | src/build-data/policy/modern.txt | 1 | ||||
-rw-r--r-- | src/cli/utils.cpp | 15 | ||||
-rw-r--r-- | src/lib/entropy/rdrand/info.txt | 16 | ||||
-rw-r--r-- | src/lib/entropy/rdrand/rdrand.cpp | 32 | ||||
-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 | 61 | ||||
-rw-r--r-- | src/tests/test_rfc6979.cpp | 4 |
9 files changed, 188 insertions, 42 deletions
diff --git a/src/build-data/policy/bsi.txt b/src/build-data/policy/bsi.txt index 2ae2ac3b2..7eb092292 100644 --- a/src/build-data/policy/bsi.txt +++ b/src/build-data/policy/bsi.txt @@ -65,6 +65,7 @@ rdseed win32_stats # rng +rdrand_rng system_rng # utils diff --git a/src/build-data/policy/modern.txt b/src/build-data/policy/modern.txt index 5a8a2f126..30b7fbfd8 100644 --- a/src/build-data/policy/modern.txt +++ b/src/build-data/policy/modern.txt @@ -60,6 +60,7 @@ simd_scalar simd_sse2 simd_altivec +rdrand_rng system_rng # entropy sources diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp index 76e445126..b0d364581 100644 --- a/src/cli/utils.cpp +++ b/src/cli/utils.cpp @@ -20,6 +20,10 @@ #include <botan/system_rng.h> #endif +#if defined(BOTAN_HAS_RDRAND_RNG) + #include <botan/rdrand_rng.h> +#endif + #if defined(BOTAN_HAS_HTTP_UTIL) #include <botan/http_util.h> #endif @@ -149,7 +153,7 @@ BOTAN_REGISTER_COMMAND("hash", Hash); class RNG final : public Command { public: - RNG() : Command("rng --system *bytes") {} + RNG() : Command("rng --system --rdrand *bytes") {} void go() override { @@ -164,6 +168,15 @@ class RNG final : public Command return; #endif } + else if(flag_set("rdrand")) + { +#if defined(BOTAN_HAS_RDRAND_RNG) + rng.reset(new Botan::RDRAND_RNG); +#else + error_output() << "rdrand_rng disabled in build\n"; + return; +#endif + } else { rng.reset(new Botan::AutoSeeded_RNG); diff --git a/src/lib/entropy/rdrand/info.txt b/src/lib/entropy/rdrand/info.txt index e3e1a2a50..ebc7fb747 100644 --- a/src/lib/entropy/rdrand/info.txt +++ b/src/lib/entropy/rdrand/info.txt @@ -1,6 +1,8 @@ define ENTROPY_SRC_RDRAND 20131128 -need_isa rdrand +<requires> +rdrand_rng +</requires> <source> rdrand.cpp @@ -9,15 +11,3 @@ rdrand.cpp <header:internal> rdrand.h </header:internal> - -<arch> -x86_32 -x86_64 -</arch> - -<cc> -gcc -clang -icc -msvc -</cc> diff --git a/src/lib/entropy/rdrand/rdrand.cpp b/src/lib/entropy/rdrand/rdrand.cpp index fb04d7b78..7fa05c605 100644 --- a/src/lib/entropy/rdrand/rdrand.cpp +++ b/src/lib/entropy/rdrand/rdrand.cpp @@ -7,40 +7,20 @@ */ #include <botan/internal/rdrand.h> +#include <botan/rdrand_rng.h> #include <botan/cpuid.h> #include <botan/build.h> -#if !defined(BOTAN_USE_GCC_INLINE_ASM) - #include <immintrin.h> -#endif - namespace Botan { size_t Intel_Rdrand::poll(RandomNumberGenerator& rng) { - if(CPUID::has_rdrand()) + if(CPUID::has_rdrand() && BOTAN_ENTROPY_INTEL_RNG_POLLS > 0) { - for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p) - { - for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i) - { - uint32_t r = 0; - -#if defined(BOTAN_USE_GCC_INLINE_ASM) - int cf = 0; + RDRAND_RNG rdrand_rng; + secure_vector<uint8_t> buf(4 * BOTAN_ENTROPY_INTEL_RNG_POLLS); - // 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) - { - rng.add_entropy_T(r); - break; - } - } - } + rdrand_rng.randomize(buf.data(), buf.size()); + rng.add_entropy(buf.data(), buf.size()); } // RDRAND is used but not trusted 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..d0fb37c16 --- /dev/null +++ b/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -0,0 +1,61 @@ +/** +* 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_with_sources(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 diff --git a/src/tests/test_rfc6979.cpp b/src/tests/test_rfc6979.cpp index 1b8e91377..8076ae70d 100644 --- a/src/tests/test_rfc6979.cpp +++ b/src/tests/test_rfc6979.cpp @@ -47,8 +47,8 @@ class RFC6979_KAT_Tests : public Text_Based_Test Botan::RFC6979_Nonce_Generator gen(hash, Q, X); result.test_eq("vector matches", gen.nonce_for(H), K); - result.test_ne("vector matches", gen.nonce_for(H+1), K); - result.test_eq("vector matches", gen.nonce_for(H), K); + result.test_ne("different output for H+1", gen.nonce_for(H+1), K); + result.test_eq("vector matches when run again", gen.nonce_for(H), K); return result; } |