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 }