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