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
rol64(uint64_t v,unsigned char b)34 static inline uint64_t rol64(uint64_t v, unsigned char b) {
35 return (v << b) | (v >> (64 - b));
36 }
idx(unsigned char x,unsigned char y)37 static inline unsigned char idx(unsigned char x, unsigned char y) {
38 return x + (5 * y);
39 }
40
41 #ifdef WORDS_BIGENDIAN
load64(const unsigned char * x)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 }
store64(unsigned char * x,uint64_t val)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 }
xor64(unsigned char * x,uint64_t val)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
LFSR86540(unsigned char * pLFSR)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
permute(PHP_SHA3_CTX * ctx)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
PHP_SHA3_Init(PHP_SHA3_CTX * ctx,int bits)150 static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
151 int bits) {
152 memset(ctx, 0, sizeof(PHP_SHA3_CTX));
153 }
154
PHP_SHA3_Update(PHP_SHA3_CTX * ctx,const unsigned char * buf,size_t count,size_t block_size)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
PHP_SHA3_Final(unsigned char * digest,PHP_SHA3_CTX * ctx,size_t block_size,size_t digest_size)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
php_sha3_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv,size_t block_size)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 #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 # 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 #define PHP_KECCAK_SPEC "b200IiIIB"
294
php_keccak_serialize(const php_hashcontext_object * hash,zend_long * magic,zval * zv)295 static zend_result php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv)
296 {
297 *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
298 return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC);
299 }
300
php_keccak_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv)301 static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
302 {
303 Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
304 int r = FAILURE;
305 if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK
306 && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == SUCCESS
307 && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
308 return SUCCESS;
309 } else {
310 return r != SUCCESS ? r : -2000;
311 }
312 }
313
314 // ==========================================================================
315
316 #define DECLARE_SHA3_OPS(bits) \
317 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
318 ZEND_ASSERT(sizeof(Keccak_HashInstance) <= sizeof(PHP_SHA3_##bits##_CTX)); \
319 Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx); \
320 } \
321 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
322 const unsigned char* input, \
323 size_t inputLen) { \
324 Keccak_HashUpdate((Keccak_HashInstance *)ctx, input, inputLen * 8); \
325 } \
326 void PHP_SHA3##bits##Final(unsigned char* digest, \
327 PHP_SHA3_##bits##_CTX* ctx) { \
328 Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \
329 } \
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
354