Botan
1.11.15
|
00001 /* 00002 * HMAC_RNG 00003 * (C) 2008-2009,2013,2015 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/hmac_rng.h> 00009 #include <botan/get_byte.h> 00010 #include <botan/entropy_src.h> 00011 #include <botan/internal/xor_buf.h> 00012 #include <algorithm> 00013 #include <chrono> 00014 00015 namespace Botan { 00016 00017 namespace { 00018 00019 void hmac_prf(MessageAuthenticationCode& prf, 00020 secure_vector<byte>& K, 00021 u32bit& counter, 00022 const std::string& label) 00023 { 00024 typedef std::chrono::high_resolution_clock clock; 00025 00026 auto timestamp = clock::now().time_since_epoch().count(); 00027 00028 prf.update(K); 00029 prf.update(label); 00030 prf.update_be(timestamp); 00031 prf.update_be(counter); 00032 prf.final(&K[0]); 00033 00034 ++counter; 00035 } 00036 00037 } 00038 00039 /* 00040 * HMAC_RNG Constructor 00041 */ 00042 HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor, 00043 MessageAuthenticationCode* prf) : 00044 m_extractor(extractor), m_prf(prf) 00045 { 00046 if(!m_prf->valid_keylength(m_extractor->output_length()) || 00047 !m_extractor->valid_keylength(m_prf->output_length())) 00048 throw Invalid_Argument("HMAC_RNG: Bad algo combination " + 00049 m_extractor->name() + " and " + 00050 m_prf->name()); 00051 00052 // First PRF inputs are all zero, as specified in section 2 00053 m_K.resize(m_prf->output_length()); 00054 00055 /* 00056 Normally we want to feedback PRF outputs to the extractor function 00057 to ensure a single bad poll does not reduce entropy. Thus in reseed 00058 we'll want to invoke the PRF before we reset the PRF key, but until 00059 the first reseed the PRF is unkeyed. Rather than trying to keep 00060 track of this, just set the initial PRF key to constant zero. 00061 Since all PRF inputs in the first reseed are constants, this 00062 amounts to suffixing the seed in the first poll with a fixed 00063 constant string. 00064 00065 The PRF key will not be used to generate outputs until after reseed 00066 sets m_seeded to true. 00067 */ 00068 secure_vector<byte> prf_key(m_extractor->output_length()); 00069 m_prf->set_key(prf_key); 00070 00071 /* 00072 Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key. 00073 00074 This will be used during the first extraction sequence; XTS values 00075 after this one are generated using the PRF. 00076 00077 If I understand the E-t-E paper correctly (specifically Section 4), 00078 using this fixed extractor key is safe to do. 00079 */ 00080 m_extractor->set_key(prf->process("Botan HMAC_RNG XTS")); 00081 } 00082 00083 /* 00084 * Generate a buffer of random bytes 00085 */ 00086 void HMAC_RNG::randomize(byte out[], size_t length) 00087 { 00088 if(!is_seeded()) 00089 { 00090 reseed(256); 00091 if(!is_seeded()) 00092 throw PRNG_Unseeded(name()); 00093 } 00094 00095 const size_t max_per_prf_iter = m_prf->output_length() / 2; 00096 00097 m_output_since_reseed += length; 00098 00099 if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED) 00100 reseed(BOTAN_RNG_RESEED_POLL_BITS); 00101 00102 /* 00103 HMAC KDF as described in E-t-E, using a CTXinfo of "rng" 00104 */ 00105 while(length) 00106 { 00107 hmac_prf(*m_prf, m_K, m_counter, "rng"); 00108 00109 const size_t copied = std::min<size_t>(length, max_per_prf_iter); 00110 00111 copy_mem(out, &m_K[0], copied); 00112 out += copied; 00113 length -= copied; 00114 } 00115 } 00116 00117 /* 00118 * Poll for entropy and reset the internal keys 00119 */ 00120 void HMAC_RNG::reseed(size_t poll_bits) 00121 { 00122 /* 00123 Using the terminology of E-t-E, XTR is the MAC function (normally 00124 HMAC) seeded with XTS (below) and we form SKM, the key material, by 00125 polling as many sources as we think needed to reach our polling 00126 goal. We then also include feedback of the current PRK so that 00127 a bad poll doesn't wipe us out. 00128 */ 00129 00130 double bits_collected = 0; 00131 00132 Entropy_Accumulator accum( 00133 [&](const byte in[], size_t in_len, double entropy_estimate) 00134 { 00135 m_extractor->update(in, in_len); 00136 bits_collected += entropy_estimate; 00137 return (bits_collected >= poll_bits); 00138 }); 00139 00140 EntropySource::poll_available_sources(accum); 00141 00142 /* 00143 * It is necessary to feed forward poll data. Otherwise, a good poll 00144 * (collecting a large amount of conditional entropy) followed by a 00145 * bad one (collecting little) would be unsafe. Do this by 00146 * generating new PRF outputs using the previous key and feeding 00147 * them into the extractor function. 00148 * 00149 * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF 00150 * output using the CTXinfo "reseed". Provide these values as input 00151 * to the extractor function. 00152 */ 00153 hmac_prf(*m_prf, m_K, m_counter, "rng"); 00154 m_extractor->update(m_K); // K is the CTXinfo=rng PRF output 00155 00156 hmac_prf(*m_prf, m_K, m_counter, "reseed"); 00157 m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output 00158 00159 /* Now derive the new PRK using everything that has been fed into 00160 the extractor, and set the PRF key to that */ 00161 m_prf->set_key(m_extractor->final()); 00162 00163 // Now generate a new PRF output to use as the XTS extractor salt 00164 hmac_prf(*m_prf, m_K, m_counter, "xts"); 00165 m_extractor->set_key(m_K); 00166 00167 // Reset state 00168 zeroise(m_K); 00169 m_counter = 0; 00170 00171 m_collected_entropy_estimate = 00172 std::min<size_t>(m_collected_entropy_estimate + bits_collected, 00173 m_extractor->output_length() * 8); 00174 00175 m_output_since_reseed = 0; 00176 } 00177 00178 bool HMAC_RNG::is_seeded() const 00179 { 00180 return (m_collected_entropy_estimate >= 256); 00181 } 00182 00183 /* 00184 * Add user-supplied entropy to the extractor input 00185 */ 00186 void HMAC_RNG::add_entropy(const byte input[], size_t length) 00187 { 00188 m_extractor->update(input, length); 00189 reseed(BOTAN_RNG_RESEED_POLL_BITS); 00190 } 00191 00192 /* 00193 * Clear memory of sensitive data 00194 */ 00195 void HMAC_RNG::clear() 00196 { 00197 m_collected_entropy_estimate = 0; 00198 m_extractor->clear(); 00199 m_prf->clear(); 00200 zeroise(m_K); 00201 m_counter = 0; 00202 } 00203 00204 /* 00205 * Return the name of this type 00206 */ 00207 std::string HMAC_RNG::name() const 00208 { 00209 return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")"; 00210 } 00211 00212 }