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 }