Coverage Report

Created: 2026-10-28 06:20

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