diff options
-rw-r--r-- | doc/relnotes/1_11_9.rst | 3 | ||||
-rw-r--r-- | src/lib/pubkey/rfc6979/info.txt | 6 | ||||
-rw-r--r-- | src/lib/pubkey/rfc6979/rfc6979.cpp | 48 | ||||
-rw-r--r-- | src/lib/pubkey/rfc6979/rfc6979.h | 29 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.cpp | 25 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.h | 2 | ||||
-rw-r--r-- | src/tests/test_rfc6979.cpp | 71 | ||||
-rw-r--r-- | src/tests/tests.cpp | 1 | ||||
-rw-r--r-- | src/tests/tests.h | 1 |
9 files changed, 175 insertions, 11 deletions
diff --git a/doc/relnotes/1_11_9.rst b/doc/relnotes/1_11_9.rst index 3ccf3fd8d..604c0d60e 100644 --- a/doc/relnotes/1_11_9.rst +++ b/doc/relnotes/1_11_9.rst @@ -5,6 +5,9 @@ Version 1.11.9, Not Yet Released added. Like the X9.31 PRNG implementation, it uses another underlying RNG for seeding material. + * An implementation of the RFC 6979 deterministic nonce generator has + been added. + * Fix a bug in certificate path validation which prevented successful validation if intermediate certificates were presented out of order. diff --git a/src/lib/pubkey/rfc6979/info.txt b/src/lib/pubkey/rfc6979/info.txt new file mode 100644 index 000000000..7055084b9 --- /dev/null +++ b/src/lib/pubkey/rfc6979/info.txt @@ -0,0 +1,6 @@ +define RFC6979_GENERATOR 20140321 + +<requires> +bigint +hmac_drbg +</requires> diff --git a/src/lib/pubkey/rfc6979/rfc6979.cpp b/src/lib/pubkey/rfc6979/rfc6979.cpp new file mode 100644 index 000000000..634b3bcb0 --- /dev/null +++ b/src/lib/pubkey/rfc6979/rfc6979.cpp @@ -0,0 +1,48 @@ +/* +* RFC 6979 Deterministic Nonce Generator +* (C) 2014 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/rfc6979.h> +#include <botan/hmac_drbg.h> +#include <botan/libstate.h> + +#include <botan/hex.h> +#include <iostream> + +namespace Botan { + +BigInt generate_rfc6979_nonce(const BigInt& x, + const BigInt& q, + const BigInt& h, + const std::string& hash) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + HMAC_DRBG rng(af.make_mac("HMAC(" + hash + ")"), nullptr); + + const size_t qlen = q.bits(); + const size_t rlen = qlen / 8 + (qlen % 8 ? 1 : 0); + + secure_vector<byte> input = BigInt::encode_1363(x, rlen); + + input += BigInt::encode_1363(h, rlen); + + rng.add_entropy(&input[0], input.size()); + + BigInt k; + + secure_vector<byte> kbits(rlen); + + while(k == 0 || k >= q) + { + rng.randomize(&kbits[0], kbits.size()); + k = BigInt::decode(kbits) >> (8*rlen - qlen); + } + + return k; + } + +} diff --git a/src/lib/pubkey/rfc6979/rfc6979.h b/src/lib/pubkey/rfc6979/rfc6979.h new file mode 100644 index 000000000..1084fe623 --- /dev/null +++ b/src/lib/pubkey/rfc6979/rfc6979.h @@ -0,0 +1,29 @@ +/* +* RFC 6979 Deterministic Nonce Generator +* (C) 2014 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RFC6979_GENERATOR__ +#define BOTAN_RFC6979_GENERATOR__ + +#include <botan/bigint.h> +#include <string> + +namespace Botan { + +/** +* @param x the secret (EC)DSA key +* @param q the group order +* @param h the message hash already reduced mod q +* @param hash the hash function used to generate h +*/ +BigInt BOTAN_DLL generate_rfc6979_nonce(const BigInt& x, + const BigInt& q, + const BigInt& h, + const std::string& hash); + +} + +#endif diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp index 3227841f0..96bd791ee 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp +++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -66,20 +66,23 @@ void HMAC_DRBG::update(const byte input[], size_t input_len) void HMAC_DRBG::reseed(size_t poll_bits) { - m_prng->reseed(poll_bits); - - if(m_prng->is_seeded()) + if(m_prng) { - secure_vector<byte> input = m_prng->random_vec(m_mac->output_length()); - update(&input[0], input.size()); - m_reseed_counter = 1; + m_prng->reseed(poll_bits); + + if(m_prng->is_seeded()) + { + secure_vector<byte> input = m_prng->random_vec(m_mac->output_length()); + update(&input[0], input.size()); + m_reseed_counter = 1; + } } } void HMAC_DRBG::add_entropy(const byte input[], size_t length) { - // Should we also poll the underlying PRNG here? update(input, length); + m_reseed_counter = 1; } bool HMAC_DRBG::is_seeded() const @@ -89,10 +92,12 @@ bool HMAC_DRBG::is_seeded() const void HMAC_DRBG::clear() { - m_mac->clear(); - m_prng->clear(); zeroise(m_V); - zeroise(m_K); + + m_mac->clear(); + + if(m_prng) + m_prng->clear(); } std::string HMAC_DRBG::name() const diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h index 43729c7fa..c3629aa15 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.h +++ b/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -41,7 +41,7 @@ class BOTAN_DLL HMAC_DRBG : public RandomNumberGenerator std::unique_ptr<MessageAuthenticationCode> m_mac; std::unique_ptr<RandomNumberGenerator> m_prng; - secure_vector<byte> m_K, m_V; + secure_vector<byte> m_V; size_t m_reseed_counter; }; diff --git a/src/tests/test_rfc6979.cpp b/src/tests/test_rfc6979.cpp new file mode 100644 index 000000000..9552b1b18 --- /dev/null +++ b/src/tests/test_rfc6979.cpp @@ -0,0 +1,71 @@ +#include "tests.h" + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + #include <botan/rfc6979.h> + #include <botan/hex.h> +#endif + +#include <iostream> + +namespace { + +size_t rfc6979_testcase(const std::string& q_str, + const std::string& x_str, + const std::string& h_str, + const std::string& exp_k_str, + const std::string& hash, + size_t testcase) + { + using namespace Botan; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + + const BigInt q(q_str); + const BigInt x(x_str); + const BigInt h(h_str); + const BigInt exp_k(exp_k_str); + + const BigInt gen_k = generate_rfc6979_nonce(x, q, h, hash); + + if(gen_k != exp_k) + { + std::cout << "RFC 6979 test #" << testcase << " failed; generated k=" + << std::hex << gen_k << "\n"; + return 1; + } + +#endif + + return 0; + } + +} + +size_t test_rfc6979() + { + using namespace Botan; + + size_t fails = 0; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + + // From RFC 6979 A.1.1 + fails += rfc6979_testcase("0x4000000000000000000020108A2E0CC0D99F8A5EF", + "0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F", + "0x01795EDF0D54DB760F156D0DAC04C0322B3A204224", + "0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B", + "SHA-256", 1); + + // DSA 1024 bits test #1 + fails += rfc6979_testcase("0x996F967F6C8E388D9E28D01E205FBA957A5698B1", + "0x411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", + "0x8151325DCDBAE9E0FF95F9F9658432DBEDFDB209", + "0x7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B", + "SHA-1", 2); + +#endif + + test_report("RFC 6979", 2, fails); + + return fails; + } diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index f1f5b5323..20aaa32d2 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -247,6 +247,7 @@ int main(int argc, char* argv[]) DEF_TEST(bcrypt); DEF_TEST(cryptobox); DEF_TEST(tss); + DEF_TEST(rfc6979); DEF_TEST(bigint); diff --git a/src/tests/tests.h b/src/tests/tests.h index 8d6ad6c3e..850a973c1 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -74,6 +74,7 @@ size_t test_bcrypt(); size_t test_passhash9(); size_t test_cryptobox(); size_t test_tss(); +size_t test_rfc6979(); size_t test_pk_keygen(); |