1 /**
2 * RFC 6979 Deterministic Nonce Generator
3 * 
4 * Copyright:
5 * (C) 2014 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.pubkey.algo.rfc6979;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO && BOTAN_HAS_RFC6979_GENERATOR):
15 
16 import botan.libstate.libstate;
17 import botan.math.bigint.bigint;
18 import botan.rng.hmac_drbg;
19 import botan.utils.types;
20 
21 /**
22 * Params:
23 *  x = the secret (EC)DSA key
24 *  q = the group order
25 *  h = the message hash already reduced mod q
26 *  hash = the hash function used to generate h
27 */
28 BigInt generateRfc6979Nonce(const ref BigInt x, const ref BigInt q, const ref BigInt h, in string hash)
29 {
30     AlgorithmFactory af = globalState().algorithmFactory();
31     
32     auto rng = scoped!HMAC_DRBG(af.makeMac("HMAC(" ~ hash ~ ")"), null);
33 
34     const size_t qlen = q.bits();
35     const size_t rlen = qlen / 8 + (qlen % 8 ? 1 : 0);
36     
37     SecureVector!ubyte input = BigInt.encode1363(x, rlen);
38     
39     input ~= BigInt.encode1363(h, rlen);
40     
41     rng.addEntropy(input.ptr, input.length);
42     
43     BigInt k;
44     
45     SecureVector!ubyte kbits = SecureVector!ubyte(rlen);
46     
47     while (k == 0 || k >= q)
48     {
49         rng.randomize(kbits.ptr, kbits.length);
50         k = BigInt.decode(kbits) >> (8*rlen - qlen);
51     }
52     
53     return k;
54 }
55 
56 static if (BOTAN_TEST):
57 import botan.test;
58 import botan.codec.hex;
59 
60 size_t rfc6979Testcase(string q_str,
61                        string x_str,
62                        string h_str,
63                        string exp_k_str,
64                        string hash,
65                        size_t testcase)
66 {
67     const BigInt q = BigInt(q_str);
68     const BigInt x = BigInt(x_str);
69     const BigInt h = BigInt(h_str);
70     const BigInt exp_k = BigInt(exp_k_str);
71     
72     const BigInt gen_k = generateRfc6979Nonce(x, q, h, hash);
73     
74     if (gen_k != exp_k)
75     {
76         logTrace("RFC 6979 test #", testcase, " failed; generated k=", gen_k.toString());
77         return 1;
78     }
79     
80     return 0;
81 }
82 
83 static if (BOTAN_HAS_TESTS && !SKIP_RFC6979_TEST) unittest
84 {
85     logDebug("Testing rfc6979.d ...");
86     
87     size_t fails = 0;
88     
89     // From RFC 6979 A.1.1
90     fails += rfc6979Testcase("0x4000000000000000000020108A2E0CC0D99F8A5EF",
91                               "0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F",
92                               "0x01795EDF0D54DB760F156D0DAC04C0322B3A204224",
93                               "0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B",
94                               "SHA-256", 1);
95     
96     // DSA 1024 bits test #1
97     fails += rfc6979Testcase("0x996F967F6C8E388D9E28D01E205FBA957A5698B1",
98                               "0x411602CB19A6CCC34494D79D98EF1E7ED5AF25F7",
99                               "0x8151325DCDBAE9E0FF95F9F9658432DBEDFDB209",
100                               "0x7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B",
101                               "SHA-1", 2);
102     
103     testReport("RFC 6979", 2, fails);
104 }