Coverage Report

Created: 2026-06-02 06:39

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