aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/relnotes/1_11_9.rst3
-rw-r--r--src/lib/pubkey/rfc6979/info.txt6
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.cpp48
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.h29
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.cpp25
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h2
-rw-r--r--src/tests/test_rfc6979.cpp71
-rw-r--r--src/tests/tests.cpp1
-rw-r--r--src/tests/tests.h1
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();