1 /** 2 * ANSI X9.31 RNG 3 * 4 * Copyright: 5 * (C) 1999-2009 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.x931_rng; 12 13 import botan.constants; 14 static if (BOTAN_HAS_X931_RNG): 15 16 import botan.rng.rng; 17 import botan.block.block_cipher; 18 import botan.utils.xor_buf; 19 import botan.utils.types; 20 import botan.utils.mem_ops; 21 import std.algorithm; 22 23 /** 24 * ANSI X9.31 RNG 25 */ 26 final class ANSIX931RNG : RandomNumberGenerator 27 { 28 public: 29 override void randomize(ubyte* output, size_t length) 30 { 31 if (!isSeeded()) 32 { 33 reseed(BOTAN_RNG_RESEED_POLL_BITS); 34 35 if (!isSeeded()) 36 throw new PRNGUnseeded(name); 37 } 38 39 while (length) 40 { 41 if (m_R_pos == m_R.length) 42 updateBuffer(); 43 44 const size_t copied = std.algorithm.min(length, m_R.length - m_R_pos); 45 46 copyMem(output, &m_R[m_R_pos], copied); 47 output += copied; 48 length -= copied; 49 m_R_pos += copied; 50 } 51 } 52 53 override bool isSeeded() const 54 { 55 return (m_V.length > 0); 56 } 57 58 override void clear() 59 { 60 m_cipher.clear(); 61 m_prng.clear(); 62 zeroise(m_R); 63 m_V.clear(); 64 65 m_R_pos = 0; 66 } 67 68 override @property string name() const 69 { 70 return "X9.31(" ~ m_cipher.name ~ ")"; 71 } 72 73 override void reseed(size_t poll_bits) 74 { 75 m_prng.reseed(poll_bits); 76 rekey(); 77 } 78 79 override void addEntropy(const(ubyte)* input, size_t length) 80 { 81 m_prng.addEntropy(input, length); 82 rekey(); 83 } 84 85 override SecureVector!ubyte randomVec(size_t bytes) { return super.randomVec(bytes); } 86 87 /** 88 * Params: 89 * cipher = the block cipher to use in this PRNG 90 * prng = the underlying PRNG for generating inputs (eg, an HMAC_RNG) 91 */ 92 this(BlockCipher cipher, 93 RandomNumberGenerator prng) 94 { 95 m_cipher = cipher; 96 m_prng = prng; 97 m_R = m_cipher.blockSize(); 98 m_R_pos = 0; 99 } 100 101 private: 102 /* 103 * Reset V and the cipher key with new values 104 */ 105 void rekey() 106 { 107 const size_t BLOCK_SIZE = m_cipher.blockSize(); 108 109 if (m_prng.isSeeded()) 110 { 111 m_cipher.setKey(m_prng.randomVec(m_cipher.maximumKeylength())); 112 113 if (m_V.length != BLOCK_SIZE) 114 m_V.resize(BLOCK_SIZE); 115 m_prng.randomize(m_V.ptr, m_V.length); 116 117 updateBuffer(); 118 } 119 } 120 121 /* 122 * Refill the internal state 123 */ 124 void updateBuffer() 125 { 126 const size_t BLOCK_SIZE = m_cipher.blockSize(); 127 128 SecureVector!ubyte DT = m_prng.randomVec(BLOCK_SIZE); 129 m_cipher.encrypt(DT); 130 131 xorBuf(m_R.ptr, m_V.ptr, DT.ptr, BLOCK_SIZE); 132 m_cipher.encrypt(m_R); 133 134 xorBuf(m_V.ptr, m_R.ptr, DT.ptr, BLOCK_SIZE); 135 m_cipher.encrypt(m_V); 136 137 m_R_pos = 0; 138 } 139 140 141 Unique!BlockCipher m_cipher; 142 Unique!RandomNumberGenerator m_prng; 143 SecureVector!ubyte m_V, m_R; 144 size_t m_R_pos; 145 }