1 /**
2 * GOST 34.11
3 * 
4 * Copyright:
5 * (C) 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.hash.gost_3411;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_GOST_34_11):
15 
16 import botan.hash.hash;
17 import botan.block.gost_28147;
18 import botan.utils.loadstor;
19 import botan.utils.rotate;
20 import botan.utils.xor_buf;
21 import botan.utils.types;
22 import botan.utils.get_byte;
23 
24 /**
25 * GOST 34.11
26 */
27 class GOST3411 : HashFunction
28 {
29 public:
30     override @property string name() const { return "GOST-R-34.11-94" ; }
31     override @property size_t outputLength() const { return 32; }
32     override @property size_t hashBlockSize() const { return 32; }
33     override HashFunction clone() const { return new GOST3411; }
34 
35     override void clear()
36     {
37         m_cipher.clear();
38         zeroise(m_sum);
39         zeroise(m_hash);
40         m_count = 0;
41         m_position = 0;
42     }
43 
44     /**
45     * GOST 34.11 Constructor
46     */
47     this() 
48     {
49         m_cipher = new GOST_28147_89(scoped!GOST_28147_89_Params("R3411_CryptoPro").Scoped_payload);
50         m_buffer = SecureVector!ubyte(32);
51         m_sum = SecureVector!ubyte(32);
52         m_hash = SecureVector!ubyte(32);
53         m_count = 0;
54         m_position = 0;
55     }
56 
57 protected:
58     /**
59     * The GOST 34.11 compression function
60     */
61     void compress_n(const(ubyte)* input, size_t blocks)
62     {
63         foreach (size_t i; 0 .. blocks)
64         {
65             for (ushort j = 0, carry = 0; j != 32; ++j)
66             {
67                 ushort s = cast(ushort)(m_sum[j] + input[32*i+j] + carry);
68                 carry = get_byte(0, s);
69                 m_sum[j] = get_byte(1, s);
70             }
71             
72             ubyte[32] S;
73             
74             ulong[4] U, V;
75             loadBigEndian(U.ptr, m_hash.ptr, 4);
76             loadBigEndian(V.ptr, input + 32*i, 4);
77             
78             foreach (size_t j; 0 .. 4)
79             {
80                 ubyte[32] key;
81                 
82                 // P transformation
83                 foreach (size_t k; 0 .. 4)
84                     foreach (size_t l; 0 .. 8)
85                         key[4*l+k] = get_byte(l, U[k]) ^ get_byte(l, V[k]);
86                 
87                 m_cipher.setKey(key.ptr, 32);
88                 m_cipher.encrypt(&m_hash[8*j], S.ptr + 8*j);
89                 
90                 if (j == 3)
91                     break;
92                 
93                 // A(x)
94                 ulong A_U = U[0];
95                 U[0] = U[1];
96                 U[1] = U[2];
97                 U[2] = U[3];
98                 U[3] = U[0] ^ A_U;
99                 
100                 if (j == 1) // C_3
101                 {
102                     U[0] ^= 0x00FF00FF00FF00FF;
103                     U[1] ^= 0xFF00FF00FF00FF00;
104                     U[2] ^= 0x00FFFF00FF0000FF;
105                     U[3] ^= 0xFF000000FFFF00FF;
106                 }
107                 
108                 // A(A(x))
109                 ulong AA_V_1 = V[0] ^ V[1];
110                 ulong AA_V_2 = V[1] ^ V[2];
111                 V[0] = V[2];
112                 V[1] = V[3];
113                 V[2] = AA_V_1;
114                 V[3] = AA_V_2;
115             }
116             
117             ubyte[32] S2;
118             
119             // 12 rounds of psi
120             S2[ 0] = S[24];
121             S2[ 1] = S[25];
122             S2[ 2] = S[26];
123             S2[ 3] = S[27];
124             S2[ 4] = S[28];
125             S2[ 5] = S[29];
126             S2[ 6] = S[30];
127             S2[ 7] = S[31];
128             S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30];
129             S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31];
130             S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30];
131             S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31];
132             S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
133             S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
134             S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28];
135             S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29];
136             S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30];
137             S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31];
138             S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28];
139             S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29];
140             S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30];
141             S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31];
142             S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30];
143             S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31];
144             S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26];
145             S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27];
146             S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28];
147             S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29];
148             S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30];
149             S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31];
150             S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28];
151             S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29];
152             
153             xorBuf(S.ptr, S2.ptr, input + 32*i, 32);
154             
155             S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30];
156             S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31];
157             
158             copyMem(S.ptr, S.ptr+2, 30);
159             S[30] = S2[0];
160             S[31] = S2[1];
161             
162             xorBuf(S.ptr, m_hash.ptr, 32);
163             
164             // 61 rounds of psi
165             S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30];
166             S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31];
167             S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28];
168             S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29];
169             S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30];
170             S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31];
171             S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30];
172             S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31];
173             S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
174             S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
175             S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28];
176             S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29];
177             S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30];
178             S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31];
179             S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24];
180             S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25];
181             S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26];
182             S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27];
183             S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28];
184             S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29];
185             S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30];
186             S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31];
187             S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^
188                      S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
189             S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^
190                      S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
191             S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^
192                      S[24] ^ S[26] ^ S[28];
193             S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^
194                      S[25] ^ S[27] ^ S[29];
195             S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^
196                      S[26] ^ S[28] ^ S[30];
197             S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^
198                      S[27] ^ S[29] ^ S[31];
199             S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28];
200             S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29];
201             S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30];
202             S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31];
203             
204             copyMem(m_hash.ptr, S2.ptr, 32);
205         }
206     }
207 
208     /**
209     * Hash additional inputs
210     */
211     override void addData(const(ubyte)* input, size_t length)
212     {
213         m_count += length;
214         
215         if (m_position)
216         {
217             bufferInsert(m_buffer, m_position, input, length);
218             
219             if (m_position + length >= hashBlockSize)
220             {
221                 compress_n(m_buffer.ptr, 1);
222                 input += (hashBlockSize - m_position);
223                 length -= (hashBlockSize - m_position);
224                 m_position = 0;
225             }
226         }
227         
228         const size_t full_blocks = length / hashBlockSize;
229         const size_t remaining   = length % hashBlockSize;
230         
231         if (full_blocks)
232             compress_n(input, full_blocks);
233         
234         bufferInsert(m_buffer, m_position, input + full_blocks * hashBlockSize, remaining);
235         m_position += remaining;
236     }
237 
238     /**
239     * Produce the final GOST 34.11 output
240     */
241     override void finalResult(ubyte* output)
242     {
243         if (m_position)
244         {
245             clearMem(m_buffer.ptr + m_position, m_buffer.length - m_position);
246             compress_n(m_buffer.ptr, 1);
247         }
248         
249         SecureVector!ubyte length_buf = SecureVector!ubyte(32);
250         const ulong bit_count = m_count * 8;
251         storeLittleEndian(bit_count, length_buf.ptr);
252         
253         SecureVector!ubyte sum_buf = m_sum.dup;
254         
255         compress_n(length_buf.ptr, 1);
256         compress_n(sum_buf.ptr, 1);
257         
258         copyMem(output, m_hash.ptr, 32);
259         clear();
260     }
261 
262     Unique!GOST_28147_89 m_cipher;
263     SecureVector!ubyte m_buffer, m_sum, m_hash;
264     size_t m_position;
265     ulong m_count;
266 }