/src/php-src/ext/hash/hash_sha3.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 | | | Author: Sara Golemon <pollita@php.net> | |
12 | | +----------------------------------------------------------------------+ |
13 | | */ |
14 | | |
15 | | #include "php_hash.h" |
16 | | #include "php_hash_sha3.h" |
17 | | |
18 | | #ifdef HAVE_SLOW_HASH3 |
19 | | // ================= slow algo ============================================== |
20 | | |
21 | | #if (defined(__APPLE__) || defined(__APPLE_CC__)) && \ |
22 | | (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) |
23 | | # if defined(__LITTLE_ENDIAN__) |
24 | | # undef WORDS_BIGENDIAN |
25 | | # else |
26 | | # if defined(__BIG_ENDIAN__) |
27 | | # define WORDS_BIGENDIAN |
28 | | # endif |
29 | | # endif |
30 | | #endif |
31 | | |
32 | | static inline uint64_t rol64(uint64_t v, unsigned char b) { |
33 | | return (v << b) | (v >> (64 - b)); |
34 | | } |
35 | | static inline unsigned char idx(unsigned char x, unsigned char y) { |
36 | | return x + (5 * y); |
37 | | } |
38 | | |
39 | | #ifdef WORDS_BIGENDIAN |
40 | | static inline uint64_t load64(const unsigned char* x) { |
41 | | signed char i; |
42 | | uint64_t ret = 0; |
43 | | for (i = 7; i >= 0; --i) { |
44 | | ret <<= 8; |
45 | | ret |= x[i]; |
46 | | } |
47 | | return ret; |
48 | | } |
49 | | static inline void store64(unsigned char* x, uint64_t val) { |
50 | | size_t i; |
51 | | for (i = 0; i < 8; ++i) { |
52 | | x[i] = val & 0xFF; |
53 | | val >>= 8; |
54 | | } |
55 | | } |
56 | | static inline void xor64(unsigned char* x, uint64_t val) { |
57 | | size_t i; |
58 | | for (i = 0; i < 8; ++i) { |
59 | | x[i] ^= val & 0xFF; |
60 | | val >>= 8; |
61 | | } |
62 | | } |
63 | | # define readLane(x, y) load64(ctx->state+sizeof(uint64_t)*idx(x, y)) |
64 | | # define writeLane(x, y, v) store64(ctx->state+sizeof(uint64_t)*idx(x, y), v) |
65 | | # define XORLane(x, y, v) xor64(ctx->state+sizeof(uint64_t)*idx(x, y), v) |
66 | | #else |
67 | | # define readLane(x, y) (((uint64_t*)ctx->state)[idx(x,y)]) |
68 | | # define writeLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] = v) |
69 | | # define XORLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] ^= v) |
70 | | #endif |
71 | | |
72 | | static inline char LFSR86540(unsigned char* pLFSR) |
73 | | { |
74 | | unsigned char LFSR = *pLFSR; |
75 | | char result = LFSR & 0x01; |
76 | | if (LFSR & 0x80) { |
77 | | // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 |
78 | | LFSR = (LFSR << 1) ^ 0x71; |
79 | | } else { |
80 | | LFSR <<= 1; |
81 | | } |
82 | | *pLFSR = LFSR; |
83 | | return result; |
84 | | } |
85 | | |
86 | | static void permute(PHP_SHA3_CTX* ctx) { |
87 | | unsigned char LFSRstate = 0x01; |
88 | | unsigned char round; |
89 | | |
90 | | for (round = 0; round < 24; ++round) { |
91 | | { // Theta step (see [Keccak Reference, Section 2.3.2]) |
92 | | uint64_t C[5], D; |
93 | | unsigned char x, y; |
94 | | for (x = 0; x < 5; ++x) { |
95 | | C[x] = readLane(x, 0) ^ readLane(x, 1) ^ |
96 | | readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4); |
97 | | } |
98 | | for (x = 0; x < 5; ++x) { |
99 | | D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1); |
100 | | for (y = 0; y < 5; ++y) { |
101 | | XORLane(x, y, D); |
102 | | } |
103 | | } |
104 | | } |
105 | | |
106 | | { // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4]) |
107 | | unsigned char x = 1, y = 0, t; |
108 | | uint64_t current = readLane(x, y); |
109 | | for (t = 0; t < 24; ++t) { |
110 | | unsigned char r = ((t + 1) * (t + 2) / 2) % 64; |
111 | | unsigned char Y = (2*x + 3*y) % 5; |
112 | | uint64_t temp; |
113 | | x = y; |
114 | | y = Y; |
115 | | temp = readLane(x, y); |
116 | | writeLane(x, y, rol64(current, r)); |
117 | | current = temp; |
118 | | } |
119 | | } |
120 | | |
121 | | { // X step (see [Keccak Reference, Section 2.3.1]) |
122 | | unsigned char x, y; |
123 | | for (y = 0; y < 5; ++y) { |
124 | | uint64_t temp[5]; |
125 | | for (x = 0; x < 5; ++x) { |
126 | | temp[x] = readLane(x, y); |
127 | | } |
128 | | for (x = 0; x < 5; ++x) { |
129 | | writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5])); |
130 | | } |
131 | | } |
132 | | } |
133 | | |
134 | | { // i step (see [Keccak Reference, Section 2.3.5]) |
135 | | unsigned char j; |
136 | | for (j = 0; j < 7; ++j) { |
137 | | if (LFSR86540(&LFSRstate)) { |
138 | | uint64_t bitPos = (1<<j) - 1; |
139 | | XORLane(0, 0, (uint64_t)1 << bitPos); |
140 | | } |
141 | | } |
142 | | } |
143 | | } |
144 | | } |
145 | | |
146 | | // ========================================================================== |
147 | | |
148 | | static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx, |
149 | | int bits) { |
150 | | memset(ctx, 0, sizeof(PHP_SHA3_CTX)); |
151 | | } |
152 | | |
153 | | static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx, |
154 | | const unsigned char* buf, |
155 | | size_t count, |
156 | | size_t block_size) { |
157 | | while (count > 0) { |
158 | | size_t len = block_size - ctx->pos; |
159 | | |
160 | | if (len > count) { |
161 | | len = count; |
162 | | } |
163 | | |
164 | | count -= len; |
165 | | |
166 | | while (len-- > 0) { |
167 | | ctx->state[ctx->pos++] ^= *(buf++); |
168 | | } |
169 | | |
170 | | if (ctx->pos >= block_size) { |
171 | | permute(ctx); |
172 | | ctx->pos = 0; |
173 | | } |
174 | | } |
175 | | } |
176 | | |
177 | | static void PHP_SHA3_Final(unsigned char* digest, |
178 | | PHP_SHA3_CTX* ctx, |
179 | | size_t block_size, |
180 | | size_t digest_size) { |
181 | | size_t len = digest_size; |
182 | | |
183 | | // Pad state to finalize |
184 | | ctx->state[ctx->pos++] ^= 0x06; |
185 | | ctx->state[block_size-1] ^= 0x80; |
186 | | permute(ctx); |
187 | | |
188 | | // Square output for digest |
189 | | for(;;) { |
190 | | int bs = (len < block_size) ? len : block_size; |
191 | | digest = zend_mempcpy(digest, ctx->state, bs); |
192 | | len -= bs; |
193 | | if (!len) break; |
194 | | permute(ctx); |
195 | | } |
196 | | |
197 | | // Zero out context |
198 | | ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX)); |
199 | | } |
200 | | |
201 | | static hash_spec_result php_sha3_unserialize(php_hashcontext_object *hash, |
202 | | zend_long magic, |
203 | | const zval *zv, |
204 | | size_t block_size) |
205 | | { |
206 | | PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context; |
207 | | hash_spec_result r = HASH_SPEC_FAILURE; |
208 | | if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC |
209 | | && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == HASH_SPEC_SUCCESS |
210 | | && ctx->pos < block_size) { |
211 | | return HASH_SPEC_SUCCESS; |
212 | | } |
213 | | |
214 | | return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; |
215 | | } |
216 | | |
217 | | // ========================================================================== |
218 | | |
219 | | #define DECLARE_SHA3_OPS(bits) \ |
220 | | void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \ |
221 | | PHP_SHA3_Init(ctx, bits); \ |
222 | | } \ |
223 | | void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \ |
224 | | const unsigned char* input, \ |
225 | | size_t inputLen) { \ |
226 | | PHP_SHA3_Update(ctx, input, inputLen, \ |
227 | | (1600 - (2 * bits)) >> 3); \ |
228 | | } \ |
229 | | void PHP_SHA3##bits##Final(unsigned char* digest, \ |
230 | | PHP_SHA3_##bits##_CTX* ctx) { \ |
231 | | PHP_SHA3_Final(digest, ctx, \ |
232 | | (1600 - (2 * bits)) >> 3, \ |
233 | | bits >> 3); \ |
234 | | } \ |
235 | | static int php_sha3##bits##_unserialize(php_hashcontext_object *hash, \ |
236 | | zend_long magic, \ |
237 | | const zval *zv) { \ |
238 | | return php_sha3_unserialize(hash, magic, zv, (1600 - (2 * bits)) >> 3); \ |
239 | | } \ |
240 | | const php_hash_ops php_hash_sha3_##bits##_ops = { \ |
241 | | "sha3-" #bits, \ |
242 | | (php_hash_init_func_t) PHP_SHA3##bits##Init, \ |
243 | | (php_hash_update_func_t) PHP_SHA3##bits##Update, \ |
244 | | (php_hash_final_func_t) PHP_SHA3##bits##Final, \ |
245 | | php_hash_copy, \ |
246 | | php_hash_serialize, \ |
247 | | php_sha3##bits##_unserialize, \ |
248 | | PHP_SHA3_SPEC, \ |
249 | | bits >> 3, \ |
250 | | (1600 - (2 * bits)) >> 3, \ |
251 | | sizeof(PHP_SHA3_##bits##_CTX), \ |
252 | | 1 \ |
253 | | } |
254 | | |
255 | | #else |
256 | | |
257 | | // ================= fast algo ============================================== |
258 | | |
259 | | #define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */ |
260 | | #include "KeccakHash.h" |
261 | | |
262 | | /* KECCAK SERIALIZATION |
263 | | |
264 | | Keccak_HashInstance consists of: |
265 | | KeccakWidth1600_SpongeInstance { |
266 | | unsigned char state[200]; |
267 | | unsigned int rate; -- fixed for digest size |
268 | | unsigned int byteIOIndex; -- in range [0, rate/8) |
269 | | int squeezing; -- 0 normally, 1 only during finalize |
270 | | } sponge; |
271 | | unsigned int fixedOutputLength; -- fixed for digest size |
272 | | unsigned char delimitedSuffix; -- fixed for digest size |
273 | | |
274 | | NB If the external sha3/ library is updated, the serialization code |
275 | | may need to be updated. |
276 | | |
277 | | The simpler SHA3 code's serialization states are not interchangeable with |
278 | | Keccak. Furthermore, the Keccak sponge state is sensitive to architecture |
279 | | -- 32-bit and 64-bit implementations produce different states. It does not |
280 | | appear that the state is sensitive to endianness. */ |
281 | | |
282 | | #if Keccak_HashInstance_ImplType == 64 |
283 | | /* corresponds to sha3/generic64lc */ |
284 | 0 | # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 100 |
285 | | #elif Keccak_HashInstance_ImplType == 32 |
286 | | /* corresponds to sha3/generic32lc */ |
287 | | # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 101 |
288 | | #else |
289 | | # error "Unknown Keccak_HashInstance_ImplType" |
290 | | #endif |
291 | 0 | #define PHP_KECCAK_SPEC "b200IiIIB" |
292 | | |
293 | | static hash_spec_result php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) |
294 | 0 | { |
295 | 0 | *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK; |
296 | 0 | return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC); |
297 | 0 | } |
298 | | |
299 | | static hash_spec_result php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) |
300 | 0 | { |
301 | 0 | Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context; |
302 | 0 | hash_spec_result r = HASH_SPEC_FAILURE; |
303 | 0 | if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK |
304 | 0 | && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == HASH_SPEC_SUCCESS |
305 | 0 | && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) { |
306 | 0 | return HASH_SPEC_SUCCESS; |
307 | 0 | } |
308 | | |
309 | 0 | return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; |
310 | 0 | } |
311 | | |
312 | | // ========================================================================== |
313 | | |
314 | | #define DECLARE_SHA3_OPS(bits) \ |
315 | 0 | void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \ |
316 | 0 | ZEND_ASSERT(sizeof(Keccak_HashInstance) <= sizeof(PHP_SHA3_##bits##_CTX)); \ |
317 | 0 | Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx); \ |
318 | 0 | } \ |
319 | | void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \ |
320 | | const unsigned char* input, \ |
321 | 0 | size_t inputLen) { \ |
322 | 0 | Keccak_HashUpdate((Keccak_HashInstance *)ctx, input, inputLen * 8); \ |
323 | 0 | } \ Unexecuted instantiation: PHP_SHA3224Update Unexecuted instantiation: PHP_SHA3256Update Unexecuted instantiation: PHP_SHA3384Update Unexecuted instantiation: PHP_SHA3512Update |
324 | | void PHP_SHA3##bits##Final(unsigned char* digest, \ |
325 | 0 | PHP_SHA3_##bits##_CTX* ctx) { \ |
326 | 0 | Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \ |
327 | 0 | } \ Unexecuted instantiation: PHP_SHA3224Final Unexecuted instantiation: PHP_SHA3256Final Unexecuted instantiation: PHP_SHA3384Final Unexecuted instantiation: PHP_SHA3512Final |
328 | | const php_hash_ops php_hash_sha3_##bits##_ops = { \ |
329 | | "sha3-" #bits, \ |
330 | | (php_hash_init_func_t) PHP_SHA3##bits##Init, \ |
331 | | (php_hash_update_func_t) PHP_SHA3##bits##Update, \ |
332 | | (php_hash_final_func_t) PHP_SHA3##bits##Final, \ |
333 | | php_hash_copy, \ |
334 | | php_keccak_serialize, \ |
335 | | php_keccak_unserialize, \ |
336 | | PHP_KECCAK_SPEC, \ |
337 | | bits >> 3, \ |
338 | | (1600 - (2 * bits)) >> 3, \ |
339 | | sizeof(PHP_SHA3_CTX), \ |
340 | | 1 \ |
341 | | } |
342 | | |
343 | | #endif |
344 | | // ================= both algo ============================================== |
345 | | |
346 | 0 | DECLARE_SHA3_OPS(224); |
347 | 0 | DECLARE_SHA3_OPS(256); |
348 | 0 | DECLARE_SHA3_OPS(384); |
349 | | DECLARE_SHA3_OPS(512); |
350 | | |
351 | | #undef DECLARE_SHA3_OPS |