1 /**
2 * HMAC_DRBG (SP800-90A)
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.rng.hmac_drbg;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_HMAC_DRBG):
15 
16 import botan.rng.rng;
17 import botan.mac.mac;
18 import botan.utils.types;
19 import botan.utils.mem_ops;
20 import std.algorithm;
21 
22 /**
23 * HMAC_DRBG (SP800-90A)
24 */
25 final class HMAC_DRBG : RandomNumberGenerator
26 {
27 public:
28     override void randomize(ubyte* output, size_t length)
29     {
30         if (!isSeeded() || m_reseed_counter > BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
31             reseed(m_mac.outputLength * 8);
32         
33         if (!isSeeded())
34             throw new PRNGUnseeded(name);
35         
36         while (length)
37         {
38             const size_t to_copy = std.algorithm.min(length, m_V.length);
39             m_V = m_mac.process(m_V);
40             copyMem(output, m_V.ptr, to_copy);
41             
42             length -= to_copy;
43             output += to_copy;
44         }
45         
46         m_reseed_counter += length;
47         
48         update(null, 0); // additional_data is always empty
49     }
50 
51     override bool isSeeded() const
52     {
53         return m_reseed_counter > 0;
54     }
55 
56     override void clear()
57     {
58         zeroise(m_V);
59         
60         m_mac.clear();
61         
62         if (m_prng)
63             m_prng.clear();
64     }
65 
66     override @property string name() const
67     {
68         return "HMAC_DRBG(" ~ m_mac.name ~ ")";
69     }
70 
71     override void reseed(size_t poll_bits)
72     {
73         if (m_prng)
74         {
75             m_prng.reseed(poll_bits);
76             
77             if (m_prng.isSeeded())
78             {
79                 SecureVector!ubyte input = m_prng.randomVec(m_mac.outputLength);
80                 update(input.ptr, input.length);
81                 m_reseed_counter = 1;
82             }
83         }
84     }
85 
86     override void addEntropy(const(ubyte)* input, size_t length)
87     {
88         update(input, length);
89         m_reseed_counter = 1;
90     }
91 
92     override SecureVector!ubyte randomVec(size_t bytes) { return super.randomVec(bytes); }
93     /**
94     * Params:
95     *  mac = the underlying mac function (eg HMAC(SHA-512))
96     *  prng = RNG used generating inputs (eg HMAC_RNG)
97     */
98     this(MessageAuthenticationCode mac,
99          RandomNumberGenerator prng)
100     { 
101         // logDebug("Loading with mac: ", mac.name);
102         import std.algorithm : fill;
103         m_mac = mac;
104         m_prng = prng;
105         m_V = SecureVector!ubyte(m_mac.outputLength);
106         fill(m_V.ptr[0 .. m_V.length], cast(ubyte)0x01);
107         m_reseed_counter = 0;
108         auto mac_key = SecureVector!ubyte(m_mac.outputLength);
109         fill(mac_key.ptr[0 .. mac_key.length], cast(ubyte)0x00);
110         m_mac.setKey(mac_key);
111     }
112 
113 private:
114     /*
115     * Reset V and the mac key with new values
116     */
117     void update(const(ubyte)* input, size_t input_len)
118     {
119         m_mac.update(m_V);
120         m_mac.update(0x00);
121         m_mac.update(input, input_len);
122         m_mac.setKey(m_mac.finished());
123         
124         m_V = m_mac.process(m_V);
125         
126         if (input_len)
127         {
128             m_mac.update(m_V);
129             m_mac.update(0x01);
130             m_mac.update(input, input_len);
131             m_mac.setKey(m_mac.finished());
132             
133             m_V = m_mac.process(m_V);
134         }
135     }
136 
137     Unique!MessageAuthenticationCode m_mac;
138     Unique!RandomNumberGenerator m_prng;
139 
140     SecureVector!ubyte m_V;
141     size_t m_reseed_counter;
142 }