1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP license, | |
8 | | that is bundled with this package in the file LICENSE, and is | |
9 | | available through the world-wide-web at the following url: | |
10 | | http://www.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Authors: Michael Wallner <mike@php.net> | |
16 | | Sara Golemon <pollita@php.net> | |
17 | +----------------------------------------------------------------------+ |
18 | */ |
19 | |
20 | /* $Id$ */ |
21 | |
22 | #include "php_hash.h" |
23 | #include "php_hash_gost.h" |
24 | #include "php_hash_gost_tables.h" |
25 | |
26 | /* {{{ Gost() |
27 | * derived from gost_compress() by Markku-Juhani Saarinen <mjos@ssh.fi> |
28 | */ |
29 | |
30 | #define round(tables, k1, k2) \ |
31 | t = (k1) + r; \ |
32 | l ^= tables[0][t & 0xff] ^ tables[1][(t >> 8) & 0xff] ^ \ |
33 | tables[2][(t >> 16) & 0xff] ^ tables[3][t >> 24]; \ |
34 | t = (k2) + l; \ |
35 | r ^= tables[0][t & 0xff] ^ tables[1][(t >> 8) & 0xff] ^ \ |
36 | tables[2][(t >> 16) & 0xff] ^ tables[3][t >> 24]; |
37 | |
38 | #define R(tables, key, h, i, t, l, r) \ |
39 | r = h[i]; \ |
40 | l = h[i + 1]; \ |
41 | round(tables, key[0], key[1]) \ |
42 | round(tables, key[2], key[3]) \ |
43 | round(tables, key[4], key[5]) \ |
44 | round(tables, key[6], key[7]) \ |
45 | round(tables, key[0], key[1]) \ |
46 | round(tables, key[2], key[3]) \ |
47 | round(tables, key[4], key[5]) \ |
48 | round(tables, key[6], key[7]) \ |
49 | round(tables, key[0], key[1]) \ |
50 | round(tables, key[2], key[3]) \ |
51 | round(tables, key[4], key[5]) \ |
52 | round(tables, key[6], key[7]) \ |
53 | round(tables, key[7], key[6]) \ |
54 | round(tables, key[5], key[4]) \ |
55 | round(tables, key[3], key[2]) \ |
56 | round(tables, key[1], key[0]) \ |
57 | t = r; \ |
58 | r = l; \ |
59 | l = t; \ |
60 | |
61 | #define X(w, u, v) \ |
62 | w[0] = u[0] ^ v[0]; \ |
63 | w[1] = u[1] ^ v[1]; \ |
64 | w[2] = u[2] ^ v[2]; \ |
65 | w[3] = u[3] ^ v[3]; \ |
66 | w[4] = u[4] ^ v[4]; \ |
67 | w[5] = u[5] ^ v[5]; \ |
68 | w[6] = u[6] ^ v[6]; \ |
69 | w[7] = u[7] ^ v[7]; |
70 | |
71 | #define P(key, w) \ |
72 | key[0] = (w[0] & 0x000000ff) | ((w[2] & 0x000000ff) << 8) | \ |
73 | ((w[4] & 0x000000ff) << 16) | ((w[6] & 0x000000ff) << 24); \ |
74 | key[1] = ((w[0] & 0x0000ff00) >> 8) | (w[2] & 0x0000ff00) | \ |
75 | ((w[4] & 0x0000ff00) << 8) | ((w[6] & 0x0000ff00) << 16); \ |
76 | key[2] = ((w[0] & 0x00ff0000) >> 16) | ((w[2] & 0x00ff0000) >> 8) | \ |
77 | (w[4] & 0x00ff0000) | ((w[6] & 0x00ff0000) << 8); \ |
78 | key[3] = ((w[0] & 0xff000000) >> 24) | ((w[2] & 0xff000000) >> 16) | \ |
79 | ((w[4] & 0xff000000) >> 8) | (w[6] & 0xff000000); \ |
80 | key[4] = (w[1] & 0x000000ff) | ((w[3] & 0x000000ff) << 8) | \ |
81 | ((w[5] & 0x000000ff) << 16) | ((w[7] & 0x000000ff) << 24); \ |
82 | key[5] = ((w[1] & 0x0000ff00) >> 8) | (w[3] & 0x0000ff00) | \ |
83 | ((w[5] & 0x0000ff00) << 8) | ((w[7] & 0x0000ff00) << 16); \ |
84 | key[6] = ((w[1] & 0x00ff0000) >> 16) | ((w[3] & 0x00ff0000) >> 8) | \ |
85 | (w[5] & 0x00ff0000) | ((w[7] & 0x00ff0000) << 8); \ |
86 | key[7] = ((w[1] & 0xff000000) >> 24) | ((w[3] & 0xff000000) >> 16) | \ |
87 | ((w[5] & 0xff000000) >> 8) | (w[7] & 0xff000000); |
88 | |
89 | #define A(x, l, r) \ |
90 | l = x[0] ^ x[2]; \ |
91 | r = x[1] ^ x[3]; \ |
92 | x[0] = x[2]; \ |
93 | x[1] = x[3]; \ |
94 | x[2] = x[4]; \ |
95 | x[3] = x[5]; \ |
96 | x[4] = x[6]; \ |
97 | x[5] = x[7]; \ |
98 | x[6] = l; \ |
99 | x[7] = r; |
100 | |
101 | #define AA(x, l, r) \ |
102 | l = x[0]; \ |
103 | r = x[2]; \ |
104 | x[0] = x[4]; \ |
105 | x[2] = x[6]; \ |
106 | x[4] = l ^ r; \ |
107 | x[6] = x[0] ^ r; \ |
108 | l = x[1]; \ |
109 | r = x[3]; \ |
110 | x[1] = x[5]; \ |
111 | x[3] = x[7]; \ |
112 | x[5] = l ^ r; \ |
113 | x[7] = x[1] ^ r; |
114 | |
115 | #define C(x) \ |
116 | x[0] ^= 0xff00ff00; \ |
117 | x[1] ^= 0xff00ff00; \ |
118 | x[2] ^= 0x00ff00ff; \ |
119 | x[3] ^= 0x00ff00ff; \ |
120 | x[4] ^= 0x00ffff00; \ |
121 | x[5] ^= 0xff0000ff; \ |
122 | x[6] ^= 0x000000ff; \ |
123 | x[7] ^= 0xff00ffff; |
124 | |
125 | #define S(s, l, r) \ |
126 | s[i] = r; \ |
127 | s[i + 1] = l; |
128 | |
129 | #define SHIFT12(u, m, s) \ |
130 | u[0] = m[0] ^ s[6]; \ |
131 | u[1] = m[1] ^ s[7]; \ |
132 | u[2] = m[2] ^ (s[0] << 16) ^ (s[0] >> 16) ^ (s[0] & 0xffff) ^ \ |
133 | (s[1] & 0xffff) ^ (s[1] >> 16) ^ (s[2] << 16) ^ s[6] ^ (s[6] << 16) ^ \ |
134 | (s[7] & 0xffff0000) ^ (s[7] >> 16); \ |
135 | u[3] = m[3] ^ (s[0] & 0xffff) ^ (s[0] << 16) ^ (s[1] & 0xffff) ^ \ |
136 | (s[1] << 16) ^ (s[1] >> 16) ^ (s[2] << 16) ^ (s[2] >> 16) ^ \ |
137 | (s[3] << 16) ^ s[6] ^ (s[6] << 16) ^ (s[6] >> 16) ^ (s[7] & 0xffff) ^ \ |
138 | (s[7] << 16) ^ (s[7] >> 16); \ |
139 | u[4] = m[4] ^ \ |
140 | (s[0] & 0xffff0000) ^ (s[0] << 16) ^ (s[0] >> 16) ^ \ |
141 | (s[1] & 0xffff0000) ^ (s[1] >> 16) ^ (s[2] << 16) ^ (s[2] >> 16) ^ \ |
142 | (s[3] << 16) ^ (s[3] >> 16) ^ (s[4] << 16) ^ (s[6] << 16) ^ \ |
143 | (s[6] >> 16) ^(s[7] & 0xffff) ^ (s[7] << 16) ^ (s[7] >> 16); \ |
144 | u[5] = m[5] ^ (s[0] << 16) ^ (s[0] >> 16) ^ (s[0] & 0xffff0000) ^ \ |
145 | (s[1] & 0xffff) ^ s[2] ^ (s[2] >> 16) ^ (s[3] << 16) ^ (s[3] >> 16) ^ \ |
146 | (s[4] << 16) ^ (s[4] >> 16) ^ (s[5] << 16) ^ (s[6] << 16) ^ \ |
147 | (s[6] >> 16) ^ (s[7] & 0xffff0000) ^ (s[7] << 16) ^ (s[7] >> 16); \ |
148 | u[6] = m[6] ^ s[0] ^ (s[1] >> 16) ^ (s[2] << 16) ^ s[3] ^ (s[3] >> 16) ^ \ |
149 | (s[4] << 16) ^ (s[4] >> 16) ^ (s[5] << 16) ^ (s[5] >> 16) ^ s[6] ^ \ |
150 | (s[6] << 16) ^ (s[6] >> 16) ^ (s[7] << 16); \ |
151 | u[7] = m[7] ^ (s[0] & 0xffff0000) ^ (s[0] << 16) ^ (s[1] & 0xffff) ^ \ |
152 | (s[1] << 16) ^ (s[2] >> 16) ^ (s[3] << 16) ^ s[4] ^ (s[4] >> 16) ^ \ |
153 | (s[5] << 16) ^ (s[5] >> 16) ^ (s[6] >> 16) ^ (s[7] & 0xffff) ^ \ |
154 | (s[7] << 16) ^ (s[7] >> 16); |
155 | |
156 | #define SHIFT16(h, v, u) \ |
157 | v[0] = h[0] ^ (u[1] << 16) ^ (u[0] >> 16); \ |
158 | v[1] = h[1] ^ (u[2] << 16) ^ (u[1] >> 16); \ |
159 | v[2] = h[2] ^ (u[3] << 16) ^ (u[2] >> 16); \ |
160 | v[3] = h[3] ^ (u[4] << 16) ^ (u[3] >> 16); \ |
161 | v[4] = h[4] ^ (u[5] << 16) ^ (u[4] >> 16); \ |
162 | v[5] = h[5] ^ (u[6] << 16) ^ (u[5] >> 16); \ |
163 | v[6] = h[6] ^ (u[7] << 16) ^ (u[6] >> 16); \ |
164 | v[7] = h[7] ^ (u[0] & 0xffff0000) ^ (u[0] << 16) ^ (u[7] >> 16) ^ \ |
165 | (u[1] & 0xffff0000) ^ (u[1] << 16) ^ (u[6] << 16) ^ (u[7] & 0xffff0000); |
166 | |
167 | #define SHIFT61(h, v) \ |
168 | h[0] = (v[0] & 0xffff0000) ^ (v[0] << 16) ^ (v[0] >> 16) ^ (v[1] >> 16) ^ \ |
169 | (v[1] & 0xffff0000) ^ (v[2] << 16) ^ (v[3] >> 16) ^ (v[4] << 16) ^ \ |
170 | (v[5] >> 16) ^ v[5] ^ (v[6] >> 16) ^ (v[7] << 16) ^ (v[7] >> 16) ^ \ |
171 | (v[7] & 0xffff); \ |
172 | h[1] = (v[0] << 16) ^ (v[0] >> 16) ^ (v[0] & 0xffff0000) ^ (v[1] & 0xffff) ^ \ |
173 | v[2] ^ (v[2] >> 16) ^ (v[3] << 16) ^ (v[4] >> 16) ^ (v[5] << 16) ^ \ |
174 | (v[6] << 16) ^ v[6] ^ (v[7] & 0xffff0000) ^ (v[7] >> 16); \ |
175 | h[2] = (v[0] & 0xffff) ^ (v[0] << 16) ^ (v[1] << 16) ^ (v[1] >> 16) ^ \ |
176 | (v[1] & 0xffff0000) ^ (v[2] << 16) ^ (v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^ \ |
177 | (v[5] >> 16) ^ v[6] ^ (v[6] >> 16) ^ (v[7] & 0xffff) ^ (v[7] << 16) ^ \ |
178 | (v[7] >> 16); \ |
179 | h[3] = (v[0] << 16) ^ (v[0] >> 16) ^ (v[0] & 0xffff0000) ^ \ |
180 | (v[1] & 0xffff0000) ^ (v[1] >> 16) ^ (v[2] << 16) ^ (v[2] >> 16) ^ v[2] ^ \ |
181 | (v[3] << 16) ^ (v[4] >> 16) ^ v[4] ^ (v[5] << 16) ^ (v[6] << 16) ^ \ |
182 | (v[7] & 0xffff) ^ (v[7] >> 16); \ |
183 | h[4] = (v[0] >> 16) ^ (v[1] << 16) ^ v[1] ^ (v[2] >> 16) ^ v[2] ^ \ |
184 | (v[3] << 16) ^ (v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^ (v[5] >> 16) ^ \ |
185 | v[5] ^ (v[6] << 16) ^ (v[6] >> 16) ^ (v[7] << 16); \ |
186 | h[5] = (v[0] << 16) ^ (v[0] & 0xffff0000) ^ (v[1] << 16) ^ (v[1] >> 16) ^ \ |
187 | (v[1] & 0xffff0000) ^ (v[2] << 16) ^ v[2] ^ (v[3] >> 16) ^ v[3] ^ \ |
188 | (v[4] << 16) ^ (v[4] >> 16) ^ v[4] ^ (v[5] << 16) ^ (v[6] << 16) ^ \ |
189 | (v[6] >> 16) ^ v[6] ^ (v[7] << 16) ^ (v[7] >> 16) ^ (v[7] & 0xffff0000); \ |
190 | h[6] = v[0] ^ v[2] ^ (v[2] >> 16) ^ v[3] ^ (v[3] << 16) ^ v[4] ^ \ |
191 | (v[4] >> 16) ^ (v[5] << 16) ^ (v[5] >> 16) ^ v[5] ^ (v[6] << 16) ^ \ |
192 | (v[6] >> 16) ^ v[6] ^ (v[7] << 16) ^ v[7]; \ |
193 | h[7] = v[0] ^ (v[0] >> 16) ^ (v[1] << 16) ^ (v[1] >> 16) ^ (v[2] << 16) ^ \ |
194 | (v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^ v[4] ^ (v[5] >> 16) ^ v[5] ^ \ |
195 | (v[6] << 16) ^ (v[6] >> 16) ^ (v[7] << 16) ^ v[7]; |
196 | |
197 | #define PASS(tables) \ |
198 | X(w, u, v); \ |
199 | P(key, w); \ |
200 | R((tables), key, h, i, t, l, r); \ |
201 | S(s, l, r); \ |
202 | if (i != 6) { \ |
203 | A(u, l, r); \ |
204 | if (i == 2) { \ |
205 | C(u); \ |
206 | } \ |
207 | AA(v, l, r); \ |
208 | } |
209 | |
210 | static inline void Gost(PHP_GOST_CTX *context, php_hash_uint32 data[8]) |
211 | { |
212 | int i; |
213 | php_hash_uint32 l, r, t, key[8], u[8], v[8], w[8], s[8], *h = context->state, *m = data; |
214 | |
215 | memcpy(u, context->state, sizeof(u)); |
216 | memcpy(v, data, sizeof(v)); |
217 | |
218 | for (i = 0; i < 8; i += 2) { |
219 | PASS(*context->tables); |
220 | } |
221 | SHIFT12(u, m, s); |
222 | SHIFT16(h, v, u); |
223 | SHIFT61(h, v); |
224 | } |
225 | /* }}} */ |
226 | |
227 | static inline void GostTransform(PHP_GOST_CTX *context, const unsigned char input[32]) |
228 | { |
229 | int i, j; |
230 | php_hash_uint32 data[8], temp = 0, save = 0; |
231 | |
232 | for (i = 0, j = 0; i < 8; ++i, j += 4) { |
233 | data[i] = ((php_hash_uint32) input[j]) | (((php_hash_uint32) input[j + 1]) << 8) | |
234 | (((php_hash_uint32) input[j + 2]) << 16) | (((php_hash_uint32) input[j + 3]) << 24); |
235 | save = context->state[i + 8]; |
236 | context->state[i + 8] += data[i] + temp; |
237 | temp = ((context->state[i + 8] < data[i]) || (context->state[i + 8] < save)) ? 1 : 0; |
238 | } |
239 | |
240 | Gost(context, data); |
241 | } |
242 | |
243 | PHP_HASH_API void PHP_GOSTInit(PHP_GOST_CTX *context) |
244 | { |
245 | memset(context, 0, sizeof(*context)); |
246 | context->tables = &tables_test; |
247 | } |
248 | |
249 | PHP_HASH_API void PHP_GOSTInitCrypto(PHP_GOST_CTX *context) |
250 | { |
251 | PHP_GOSTInit(context); |
252 | context->tables = &tables_crypto; |
253 | } |
254 | |
255 | static const php_hash_uint32 MAX32 = 0xffffffffLU; |
256 | |
257 | PHP_HASH_API void PHP_GOSTUpdate(PHP_GOST_CTX *context, const unsigned char *input, size_t len) |
258 | { |
259 | if ((MAX32 - context->count[0]) < (len * 8)) { |
260 | context->count[1]++; |
261 | context->count[0] = MAX32 - context->count[0]; |
262 | context->count[0] = (len * 8) - context->count[0]; |
263 | } else { |
264 | context->count[0] += len * 8; |
265 | } |
266 | |
267 | if (context->length + len < 32) { |
268 | memcpy(&context->buffer[context->length], input, len); |
269 | context->length += len; |
270 | } else { |
271 | size_t i = 0, r = (context->length + len) % 32; |
272 | |
273 | if (context->length) { |
274 | i = 32 - context->length; |
275 | memcpy(&context->buffer[context->length], input, i); |
276 | GostTransform(context, context->buffer); |
277 | } |
278 | |
279 | for (; i + 32 <= len; i += 32) { |
280 | GostTransform(context, input + i); |
281 | } |
282 | |
283 | memcpy(context->buffer, input + i, r); |
284 | memset(&context->buffer[r], 0, 32 - r); |
285 | context->length = r; |
286 | } |
287 | } |
288 | |
289 | PHP_HASH_API void PHP_GOSTFinal(unsigned char digest[32], PHP_GOST_CTX *context) |
290 | { |
291 | php_hash_uint32 i, j, l[8] = {0}; |
292 | |
293 | if (context->length) { |
294 | GostTransform(context, context->buffer); |
295 | } |
296 | |
297 | memcpy(l, context->count, sizeof(context->count)); |
298 | Gost(context, l); |
299 | memcpy(l, &context->state[8], sizeof(l)); |
300 | Gost(context, l); |
301 | |
302 | for (i = 0, j = 0; j < 32; i++, j += 4) { |
303 | digest[j] = (unsigned char) (context->state[i] & 0xff); |
304 | digest[j + 1] = (unsigned char) ((context->state[i] >> 8) & 0xff); |
305 | digest[j + 2] = (unsigned char) ((context->state[i] >> 16) & 0xff); |
306 | digest[j + 3] = (unsigned char) ((context->state[i] >> 24) & 0xff); |
307 | } |
308 | |
309 | memset(context, 0, sizeof(*context)); |
310 | } |
311 | |
312 | const php_hash_ops php_hash_gost_ops = { |
313 | (php_hash_init_func_t) PHP_GOSTInit, |
314 | (php_hash_update_func_t) PHP_GOSTUpdate, |
315 | (php_hash_final_func_t) PHP_GOSTFinal, |
316 | (php_hash_copy_func_t) php_hash_copy, |
317 | 32, |
318 | 32, |
319 | sizeof(PHP_GOST_CTX) |
320 | }; |
321 | |
322 | const php_hash_ops php_hash_gost_crypto_ops = { |
323 | (php_hash_init_func_t) PHP_GOSTInitCrypto, |
324 | (php_hash_update_func_t) PHP_GOSTUpdate, |
325 | (php_hash_final_func_t) PHP_GOSTFinal, |
326 | (php_hash_copy_func_t) php_hash_copy, |
327 | 32, |
328 | 32, |
329 | sizeof(PHP_GOST_CTX) |
330 | }; |
331 | |
332 | /* |
333 | * Local variables: |
334 | * tab-width: 4 |
335 | * c-basic-offset: 4 |
336 | * End: |
337 | * vim600: sw=4 ts=4 fdm=marker |
338 | * vim<600: sw=4 ts=4 |
339 | */ |
340 | |