Coverage Report

Created: 2025-07-23 06:33

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