Coverage Report

Created: 2025-07-23 06:33

/src/php-src/ext/hash/hash_snefru.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_snefru.h"
20
#include "php_hash_snefru_tables.h"
21
22
#define round(L, C, N, SB)  \
23
9.15M
  SBE = SB[C & 0xff]; \
24
9.15M
  L ^= SBE; \
25
9.15M
  N ^= SBE
26
27
#ifndef DBG_SNEFRU
28
#define DBG_SNEFRU 0
29
#endif
30
31
#if DBG_SNEFRU
32
void ph(uint32_t h[16])
33
{
34
  int i;
35
  for (i = 0; i < 16; i++)
36
    printf ("%08lx", h[i]); printf("\n");
37
}
38
#endif
39
40
static inline void Snefru(uint32_t input[16])
41
17.8k
{
42
17.8k
  static const int shifts[4] = {16, 8, 16, 24};
43
17.8k
  int b, index, rshift, lshift;
44
17.8k
  const uint32_t *t0,*t1;
45
17.8k
  uint32_t SBE,B00,B01,B02,B03,B04,B05,B06,B07,B08,B09,B10,B11,B12,B13,B14,B15;
46
47
17.8k
  B00 = input[0];
48
17.8k
  B01 = input[1];
49
17.8k
  B02 = input[2];
50
17.8k
  B03 = input[3];
51
17.8k
  B04 = input[4];
52
17.8k
  B05 = input[5];
53
17.8k
  B06 = input[6];
54
17.8k
  B07 = input[7];
55
17.8k
  B08 = input[8];
56
17.8k
  B09 = input[9];
57
17.8k
  B10 = input[10];
58
17.8k
  B11 = input[11];
59
17.8k
  B12 = input[12];
60
17.8k
  B13 = input[13];
61
17.8k
  B14 = input[14];
62
17.8k
  B15 = input[15];
63
64
160k
  for (index = 0; index < 8; index++) {
65
143k
    t0 = tables[2*index+0];
66
143k
    t1 = tables[2*index+1];
67
715k
    for (b = 0; b < 4; b++) {
68
572k
      round(B15, B00, B01, t0);
69
572k
      round(B00, B01, B02, t0);
70
572k
      round(B01, B02, B03, t1);
71
572k
      round(B02, B03, B04, t1);
72
572k
      round(B03, B04, B05, t0);
73
572k
      round(B04, B05, B06, t0);
74
572k
      round(B05, B06, B07, t1);
75
572k
      round(B06, B07, B08, t1);
76
572k
      round(B07, B08, B09, t0);
77
572k
      round(B08, B09, B10, t0);
78
572k
      round(B09, B10, B11, t1);
79
572k
      round(B10, B11, B12, t1);
80
572k
      round(B11, B12, B13, t0);
81
572k
      round(B12, B13, B14, t0);
82
572k
      round(B13, B14, B15, t1);
83
572k
      round(B14, B15, B00, t1);
84
85
572k
      rshift = shifts[b];
86
572k
      lshift = 32-rshift;
87
88
572k
      B00 = (B00 >> rshift) | (B00 << lshift);
89
572k
      B01 = (B01 >> rshift) | (B01 << lshift);
90
572k
      B02 = (B02 >> rshift) | (B02 << lshift);
91
572k
      B03 = (B03 >> rshift) | (B03 << lshift);
92
572k
      B04 = (B04 >> rshift) | (B04 << lshift);
93
572k
      B05 = (B05 >> rshift) | (B05 << lshift);
94
572k
      B06 = (B06 >> rshift) | (B06 << lshift);
95
572k
      B07 = (B07 >> rshift) | (B07 << lshift);
96
572k
      B08 = (B08 >> rshift) | (B08 << lshift);
97
572k
      B09 = (B09 >> rshift) | (B09 << lshift);
98
572k
      B10 = (B10 >> rshift) | (B10 << lshift);
99
572k
      B11 = (B11 >> rshift) | (B11 << lshift);
100
572k
      B12 = (B12 >> rshift) | (B12 << lshift);
101
572k
      B13 = (B13 >> rshift) | (B13 << lshift);
102
572k
      B14 = (B14 >> rshift) | (B14 << lshift);
103
572k
      B15 = (B15 >> rshift) | (B15 << lshift);
104
572k
    }
105
143k
  }
106
17.8k
  input[0] ^= B15;
107
17.8k
  input[1] ^= B14;
108
17.8k
  input[2] ^= B13;
109
17.8k
  input[3] ^= B12;
110
17.8k
  input[4] ^= B11;
111
17.8k
  input[5] ^= B10;
112
17.8k
  input[6] ^= B09;
113
17.8k
  input[7] ^= B08;
114
#if DBG_SNEFRU
115
  ph(input);
116
#endif
117
17.8k
}
118
119
static inline void SnefruTransform(PHP_SNEFRU_CTX *context, const unsigned char input[32])
120
17.8k
{
121
17.8k
  int i, j;
122
123
160k
  for (i = 0, j = 0; i < 32; i += 4, ++j) {
124
142k
    context->state[8+j] = ((unsigned)input[i] << 24) | ((unsigned)input[i+1] << 16) |
125
142k
                ((unsigned)input[i+2] << 8) | (unsigned)input[i+3];
126
142k
  }
127
17.8k
  Snefru(context->state);
128
17.8k
  ZEND_SECURE_ZERO(&context->state[8], sizeof(uint32_t) * 8);
129
17.8k
}
130
131
PHP_HASH_API void PHP_SNEFRUInit(PHP_SNEFRU_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
132
63
{
133
63
  memset(context, 0, sizeof(*context));
134
63
}
135
136
static const uint32_t MAX32 = 0xffffffffLU;
137
138
PHP_HASH_API void PHP_SNEFRUUpdate(PHP_SNEFRU_CTX *context, const unsigned char *input, size_t len)
139
36
{
140
36
  if ((MAX32 - context->count[1]) < (len * 8)) {
141
10
    context->count[0]++;
142
10
    context->count[1] = MAX32 - context->count[1];
143
10
    context->count[1] = ((uint32_t) len * 8) - context->count[1];
144
26
  } else {
145
26
    context->count[1] += (uint32_t) len * 8;
146
26
  }
147
148
36
  if (context->length + len < 32) {
149
3
    memcpy(&context->buffer[context->length], input, len);
150
3
    context->length += (unsigned char)len;
151
33
  } else {
152
33
    size_t i = 0, r = (context->length + len) % 32;
153
154
33
    if (context->length) {
155
9
      i = 32 - context->length;
156
9
      memcpy(&context->buffer[context->length], input, i);
157
9
      SnefruTransform(context, context->buffer);
158
9
    }
159
160
17.8k
    for (; i + 32 <= len; i += 32) {
161
17.7k
      SnefruTransform(context, input + i);
162
17.7k
    }
163
164
33
    memcpy(context->buffer, input + i, r);
165
33
    ZEND_SECURE_ZERO(&context->buffer[r], 32 - r);
166
33
    context->length = (unsigned char)r;
167
33
  }
168
36
}
169
170
PHP_HASH_API void PHP_SNEFRUFinal(unsigned char digest[32], PHP_SNEFRU_CTX *context)
171
36
{
172
36
  uint32_t i, j;
173
174
36
  if (context->length) {
175
32
    SnefruTransform(context, context->buffer);
176
32
  }
177
178
36
  context->state[14] = context->count[0];
179
36
  context->state[15] = context->count[1];
180
36
  Snefru(context->state);
181
182
324
  for (i = 0, j = 0; j < 32; i++, j += 4) {
183
288
    digest[j] = (unsigned char) ((context->state[i] >> 24) & 0xff);
184
288
    digest[j + 1] = (unsigned char) ((context->state[i] >> 16) & 0xff);
185
288
    digest[j + 2] = (unsigned char) ((context->state[i] >> 8) & 0xff);
186
288
    digest[j + 3] = (unsigned char) (context->state[i] & 0xff);
187
288
  }
188
189
36
  ZEND_SECURE_ZERO(context, sizeof(*context));
190
36
}
191
192
static int php_snefru_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
193
63
{
194
63
  PHP_SNEFRU_CTX *ctx = (PHP_SNEFRU_CTX *) hash->context;
195
63
  int r = FAILURE;
196
63
  if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
197
63
    && (r = php_hash_unserialize_spec(hash, zv, PHP_SNEFRU_SPEC)) == SUCCESS
198
63
    && ctx->length < sizeof(ctx->buffer)) {
199
36
    return SUCCESS;
200
36
  } else {
201
27
    return r != SUCCESS ? r : -2000;
202
27
  }
203
63
}
204
205
const php_hash_ops php_hash_snefru_ops = {
206
  "snefru",
207
  (php_hash_init_func_t) PHP_SNEFRUInit,
208
  (php_hash_update_func_t) PHP_SNEFRUUpdate,
209
  (php_hash_final_func_t) PHP_SNEFRUFinal,
210
  php_hash_copy,
211
  php_hash_serialize,
212
  php_snefru_unserialize,
213
  PHP_SNEFRU_SPEC,
214
  32,
215
  32,
216
  sizeof(PHP_SNEFRU_CTX),
217
  1
218
};