1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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
Gost(PHP_GOST_CTX * context,uint32_t data[8])210 static inline void Gost(PHP_GOST_CTX *context, uint32_t data[8])
211 {
212 int i;
213 uint32_t 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
GostTransform(PHP_GOST_CTX * context,const unsigned char input[32])227 static inline void GostTransform(PHP_GOST_CTX *context, const unsigned char input[32])
228 {
229 int i, j;
230 uint32_t data[8], temp = 0;
231
232 for (i = 0, j = 0; i < 8; ++i, j += 4) {
233 data[i] = ((uint32_t) input[j]) | (((uint32_t) input[j + 1]) << 8) |
234 (((uint32_t) input[j + 2]) << 16) | (((uint32_t) input[j + 3]) << 24);
235 context->state[i + 8] += data[i] + temp;
236 temp = context->state[i + 8] < data[i] ? 1 : (context->state[i + 8] == data[i] ? temp : 0);
237 }
238
239 Gost(context, data);
240 }
241
PHP_GOSTInit(PHP_GOST_CTX * context)242 PHP_HASH_API void PHP_GOSTInit(PHP_GOST_CTX *context)
243 {
244 memset(context, 0, sizeof(*context));
245 context->tables = &tables_test;
246 }
247
PHP_GOSTInitCrypto(PHP_GOST_CTX * context)248 PHP_HASH_API void PHP_GOSTInitCrypto(PHP_GOST_CTX *context)
249 {
250 PHP_GOSTInit(context);
251 context->tables = &tables_crypto;
252 }
253
254 static const uint32_t MAX32 = 0xffffffffLU;
255
PHP_GOSTUpdate(PHP_GOST_CTX * context,const unsigned char * input,size_t len)256 PHP_HASH_API void PHP_GOSTUpdate(PHP_GOST_CTX *context, const unsigned char *input, size_t len)
257 {
258 if ((MAX32 - context->count[0]) < (len * 8)) {
259 context->count[1]++;
260 context->count[0] = MAX32 - context->count[0];
261 context->count[0] = (len * 8) - context->count[0];
262 } else {
263 context->count[0] += len * 8;
264 }
265
266 if (context->length + len < 32) {
267 memcpy(&context->buffer[context->length], input, len);
268 context->length += len;
269 } else {
270 size_t i = 0, r = (context->length + len) % 32;
271
272 if (context->length) {
273 i = 32 - context->length;
274 memcpy(&context->buffer[context->length], input, i);
275 GostTransform(context, context->buffer);
276 }
277
278 for (; i + 32 <= len; i += 32) {
279 GostTransform(context, input + i);
280 }
281
282 memcpy(context->buffer, input + i, r);
283 ZEND_SECURE_ZERO(&context->buffer[r], 32 - r);
284 context->length = r;
285 }
286 }
287
PHP_GOSTFinal(unsigned char digest[32],PHP_GOST_CTX * context)288 PHP_HASH_API void PHP_GOSTFinal(unsigned char digest[32], PHP_GOST_CTX *context)
289 {
290 uint32_t i, j, l[8] = {0};
291
292 if (context->length) {
293 GostTransform(context, context->buffer);
294 }
295
296 memcpy(l, context->count, sizeof(context->count));
297 Gost(context, l);
298 memcpy(l, &context->state[8], sizeof(l));
299 Gost(context, l);
300
301 for (i = 0, j = 0; j < 32; i++, j += 4) {
302 digest[j] = (unsigned char) (context->state[i] & 0xff);
303 digest[j + 1] = (unsigned char) ((context->state[i] >> 8) & 0xff);
304 digest[j + 2] = (unsigned char) ((context->state[i] >> 16) & 0xff);
305 digest[j + 3] = (unsigned char) ((context->state[i] >> 24) & 0xff);
306 }
307
308 ZEND_SECURE_ZERO(context, sizeof(*context));
309 }
310
311 const php_hash_ops php_hash_gost_ops = {
312 (php_hash_init_func_t) PHP_GOSTInit,
313 (php_hash_update_func_t) PHP_GOSTUpdate,
314 (php_hash_final_func_t) PHP_GOSTFinal,
315 (php_hash_copy_func_t) php_hash_copy,
316 32,
317 32,
318 sizeof(PHP_GOST_CTX)
319 };
320
321 const php_hash_ops php_hash_gost_crypto_ops = {
322 (php_hash_init_func_t) PHP_GOSTInitCrypto,
323 (php_hash_update_func_t) PHP_GOSTUpdate,
324 (php_hash_final_func_t) PHP_GOSTFinal,
325 (php_hash_copy_func_t) php_hash_copy,
326 32,
327 32,
328 sizeof(PHP_GOST_CTX)
329 };
330
331 /*
332 * Local variables:
333 * tab-width: 4
334 * c-basic-offset: 4
335 * End:
336 * vim600: sw=4 ts=4 fdm=marker
337 * vim<600: sw=4 ts=4
338 */
339