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 memcpy(digest, ctx->state, bs);
194 digest += bs;
195 len -= bs;
196 if (!len) break;
197 permute(ctx);
198 }
199
200 // Zero out context
201 ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
202 }
203
php_sha3_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv,size_t block_size)204 static int php_sha3_unserialize(php_hashcontext_object *hash,
205 zend_long magic,
206 const zval *zv,
207 size_t block_size)
208 {
209 PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context;
210 int r = FAILURE;
211 if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
212 && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == SUCCESS
213 && ctx->pos < block_size) {
214 return SUCCESS;
215 } else {
216 return r != SUCCESS ? r : -2000;
217 }
218 }
219
220 // ==========================================================================
221
222 #define DECLARE_SHA3_OPS(bits) \
223 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
224 PHP_SHA3_Init(ctx, bits); \
225 } \
226 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
227 const unsigned char* input, \
228 size_t inputLen) { \
229 PHP_SHA3_Update(ctx, input, inputLen, \
230 (1600 - (2 * bits)) >> 3); \
231 } \
232 void PHP_SHA3##bits##Final(unsigned char* digest, \
233 PHP_SHA3_##bits##_CTX* ctx) { \
234 PHP_SHA3_Final(digest, ctx, \
235 (1600 - (2 * bits)) >> 3, \
236 bits >> 3); \
237 } \
238 static int php_sha3##bits##_unserialize(php_hashcontext_object *hash, \
239 zend_long magic, \
240 const zval *zv) { \
241 return php_sha3_unserialize(hash, magic, zv, (1600 - (2 * bits)) >> 3); \
242 } \
243 const php_hash_ops php_hash_sha3_##bits##_ops = { \
244 "sha3-" #bits, \
245 (php_hash_init_func_t) PHP_SHA3##bits##Init, \
246 (php_hash_update_func_t) PHP_SHA3##bits##Update, \
247 (php_hash_final_func_t) PHP_SHA3##bits##Final, \
248 php_hash_copy, \
249 php_hash_serialize, \
250 php_sha3##bits##_unserialize, \
251 PHP_SHA3_SPEC, \
252 bits >> 3, \
253 (1600 - (2 * bits)) >> 3, \
254 sizeof(PHP_SHA3_##bits##_CTX), \
255 1 \
256 }
257
258 #else
259
260 // ================= fast algo ==============================================
261
262 #define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
263 #include "KeccakHash.h"
264
265 /* KECCAK SERIALIZATION
266
267 Keccak_HashInstance consists of:
268 KeccakWidth1600_SpongeInstance {
269 unsigned char state[200];
270 unsigned int rate; -- fixed for digest size
271 unsigned int byteIOIndex; -- in range [0, rate/8)
272 int squeezing; -- 0 normally, 1 only during finalize
273 } sponge;
274 unsigned int fixedOutputLength; -- fixed for digest size
275 unsigned char delimitedSuffix; -- fixed for digest size
276
277 NB If the external sha3/ library is updated, the serialization code
278 may need to be updated.
279
280 The simpler SHA3 code's serialization states are not interchangeable with
281 Keccak. Furthermore, the Keccak sponge state is sensitive to architecture
282 -- 32-bit and 64-bit implementations produce different states. It does not
283 appear that the state is sensitive to endianness. */
284
285 #if Keccak_HashInstance_ImplType == 64
286 /* corresponds to sha3/generic64lc */
287 # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 100
288 #elif Keccak_HashInstance_ImplType == 32
289 /* corresponds to sha3/generic32lc */
290 # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 101
291 #else
292 # error "Unknown Keccak_HashInstance_ImplType"
293 #endif
294 #define PHP_KECCAK_SPEC "b200IiIIB"
295
php_keccak_serialize(const php_hashcontext_object * hash,zend_long * magic,zval * zv)296 static int php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv)
297 {
298 *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
299 return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC);
300 }
301
php_keccak_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv)302 static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
303 {
304 Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
305 int r = FAILURE;
306 if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK
307 && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == SUCCESS
308 && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
309 return SUCCESS;
310 } else {
311 return r != SUCCESS ? r : -2000;
312 }
313 }
314
315 // ==========================================================================
316
317 #define DECLARE_SHA3_OPS(bits) \
318 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
319 ZEND_ASSERT(sizeof(Keccak_HashInstance) <= sizeof(PHP_SHA3_##bits##_CTX)); \
320 Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx); \
321 } \
322 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
323 const unsigned char* input, \
324 size_t inputLen) { \
325 Keccak_HashUpdate((Keccak_HashInstance *)ctx, input, inputLen * 8); \
326 } \
327 void PHP_SHA3##bits##Final(unsigned char* digest, \
328 PHP_SHA3_##bits##_CTX* ctx) { \
329 Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \
330 } \
331 const php_hash_ops php_hash_sha3_##bits##_ops = { \
332 "sha3-" #bits, \
333 (php_hash_init_func_t) PHP_SHA3##bits##Init, \
334 (php_hash_update_func_t) PHP_SHA3##bits##Update, \
335 (php_hash_final_func_t) PHP_SHA3##bits##Final, \
336 php_hash_copy, \
337 php_keccak_serialize, \
338 php_keccak_unserialize, \
339 PHP_KECCAK_SPEC, \
340 bits >> 3, \
341 (1600 - (2 * bits)) >> 3, \
342 sizeof(PHP_SHA3_CTX), \
343 1 \
344 }
345
346 #endif
347 // ================= both algo ==============================================
348
349 DECLARE_SHA3_OPS(224);
350 DECLARE_SHA3_OPS(256);
351 DECLARE_SHA3_OPS(384);
352 DECLARE_SHA3_OPS(512);
353
354 #undef DECLARE_SHA3_OPS
355