Skip to content

Commit d244b54

Browse files
committed
Implement SHA3 hashing algorithm
1 parent fdb1434 commit d244b54

File tree

8 files changed

+365
-3
lines changed

8 files changed

+365
-3
lines changed

ext/hash/config.m4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ if test "$PHP_HASH" != "no"; then
2727

2828
EXT_HASH_SOURCES="hash.c hash_md.c hash_sha.c hash_ripemd.c hash_haval.c \
2929
hash_tiger.c hash_gost.c hash_snefru.c hash_whirlpool.c hash_adler32.c \
30-
hash_crc32.c hash_fnv.c hash_joaat.c"
30+
hash_crc32.c hash_fnv.c hash_joaat.c hash_sha3.c"
3131
EXT_HASH_HEADERS="php_hash.h php_hash_md.h php_hash_sha.h php_hash_ripemd.h \
3232
php_hash_haval.h php_hash_tiger.h php_hash_gost.h php_hash_snefru.h \
3333
php_hash_whirlpool.h php_hash_adler32.h php_hash_crc32.h \
34-
php_hash_fnv.h php_hash_joaat.h"
34+
php_hash_fnv.h php_hash_joaat.h php_hash_sha3.h"
3535

3636
PHP_NEW_EXTENSION(hash, $EXT_HASH_SOURCES, $ext_shared)
3737
ifdef([PHP_INSTALL_HEADERS], [

ext/hash/hash.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,10 @@ PHP_MINIT_FUNCTION(hash)
10141014
php_hash_register_algo("sha256", &php_hash_sha256_ops);
10151015
php_hash_register_algo("sha384", &php_hash_sha384_ops);
10161016
php_hash_register_algo("sha512", &php_hash_sha512_ops);
1017+
php_hash_register_algo("sha3-224", &php_hash_sha3_224_ops);
1018+
php_hash_register_algo("sha3-256", &php_hash_sha3_256_ops);
1019+
php_hash_register_algo("sha3-384", &php_hash_sha3_384_ops);
1020+
php_hash_register_algo("sha3-512", &php_hash_sha3_512_ops);
10171021
php_hash_register_algo("ripemd128", &php_hash_ripemd128_ops);
10181022
php_hash_register_algo("ripemd160", &php_hash_ripemd160_ops);
10191023
php_hash_register_algo("ripemd256", &php_hash_ripemd256_ops);

ext/hash/hash_sha3.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#include "php_hash_sha3.h"
2+
3+
#if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
4+
(defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
5+
# if defined(__LITTLE_ENDIAN__)
6+
# undef WORDS_BIGENDIAN
7+
# else
8+
# if defined(__BIG_ENDIAN__)
9+
# define WORDS_BIGENDIAN
10+
# endif
11+
# endif
12+
#endif
13+
14+
inline php_hash_uint64 rol64(php_hash_uint64 v, unsigned char b) {
15+
return (v << b) | (v >> (64 - b));
16+
}
17+
inline unsigned char idx(unsigned char x, unsigned char y) {
18+
return x + (5 * y);
19+
}
20+
21+
#ifdef WORDS_BIGENDIAN
22+
inline php_hash_uint64 load64(const unsigned char* x) {
23+
php_hash_uint64 ret = 0;
24+
for (unsigned char i = 7; i >= 0; --i) {
25+
ret <<= 8;
26+
ret |= x[i];
27+
}
28+
return ret;
29+
}
30+
inline void store64(const unsigned char* x, php_hash_uint64 val) {
31+
for (unsigned char i = 0; i < 8; ++i) {
32+
x[i] = val & 0xFF;
33+
val >>= 8;
34+
}
35+
}
36+
inline void xor64(const unsigned char* x, php_hash_uint64 val) {
37+
for (unsigned char i = 0; i < 8; ++i) {
38+
x[i] ^= val & 0xFF;
39+
val >>= 8;
40+
}
41+
}
42+
# define readLane(x, y) load64(ctx->state+sizeof(php_hash_uint64)*idx(x, y))
43+
# define writeLane(x, y, v) store64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
44+
# define XORLane(x, y, v) xor64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
45+
#else
46+
# define readLane(x, y) (((php_hash_uint64*)ctx->state)[idx(x,y)])
47+
# define writeLane(x, y, v) (((php_hash_uint64*)ctx->state)[idx(x,y)] = v)
48+
# define XORLane(x, y, v) (((php_hash_uint64*)ctx->state)[idx(x,y)] ^= v)
49+
#endif
50+
51+
inline char LFSR86540(unsigned char* pLFSR)
52+
{
53+
unsigned char LFSR = *pLFSR;
54+
char result = LFSR & 0x01;
55+
if (LFSR & 0x80) {
56+
// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
57+
LFSR = (LFSR << 1) ^ 0x71;
58+
} else {
59+
LFSR <<= 1;
60+
}
61+
*pLFSR = LFSR;
62+
return result;
63+
}
64+
65+
static void permute(PHP_SHA3_CTX* ctx) {
66+
unsigned char LFSRstate = 0x01;
67+
unsigned char round;
68+
69+
for (round = 0; round < 24; ++round) {
70+
{ // Theta step (see [Keccak Reference, Section 2.3.2])
71+
php_hash_uint64 C[5], D;
72+
unsigned char x, y;
73+
for (x = 0; x < 5; ++x) {
74+
C[x] = readLane(x, 0) ^ readLane(x, 1) ^
75+
readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
76+
}
77+
for (x = 0; x < 5; ++x) {
78+
D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
79+
for (y = 0; y < 5; ++y) {
80+
XORLane(x, y, D);
81+
}
82+
}
83+
}
84+
85+
{ // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
86+
unsigned char x = 1, y = 0, t;
87+
php_hash_uint64 current = readLane(x, y);
88+
for (t = 0; t < 24; ++t) {
89+
unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
90+
unsigned char Y = (2*x + 3*y) % 5;
91+
x = y; y = Y;
92+
php_hash_uint64 temp = readLane(x, y);
93+
writeLane(x, y, rol64(current, r));
94+
current = temp;
95+
}
96+
}
97+
98+
{ // X step (see [Keccak Reference, Section 2.3.1])
99+
unsigned char x, y;
100+
for (y = 0; y < 5; ++y) {
101+
php_hash_uint64 temp[5];
102+
for (x = 0; x < 5; ++x) {
103+
temp[x] = readLane(x, y);
104+
}
105+
for (x = 0; x < 5; ++x) {
106+
writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
107+
}
108+
}
109+
}
110+
111+
{ // i step (see [Keccak Reference, Section 2.3.5])
112+
unsigned char j;
113+
for (j = 0; j < 7; ++j) {
114+
if (LFSR86540(&LFSRstate)) {
115+
php_hash_uint64 bitPos = (1<<j) - 1;
116+
XORLane(0, 0, (php_hash_uint64)1 << bitPos);
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
// ==========================================================================
124+
125+
static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
126+
int bits) {
127+
memset(ctx, 0, sizeof(PHP_SHA3_CTX));
128+
}
129+
130+
static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
131+
const unsigned char* buf,
132+
unsigned int count,
133+
int block_size) {
134+
while (count > 0) {
135+
int len = block_size - ctx->pos;
136+
if (len > count) len = count;
137+
count -= len;
138+
while (len-- > 0) {
139+
ctx->state[ctx->pos++] ^= *(buf++);
140+
}
141+
if (ctx->pos >= block_size) {
142+
permute(ctx);
143+
ctx->pos = 0;
144+
}
145+
}
146+
}
147+
148+
static void PHP_SHA3_Final(unsigned char* digest,
149+
PHP_SHA3_CTX* ctx,
150+
int block_size,
151+
int digest_size) {
152+
int len = digest_size;
153+
154+
// Pad state to finalize
155+
ctx->state[ctx->pos++] ^= 0x06;
156+
ctx->state[block_size-1] ^= 0x80;
157+
permute(ctx);
158+
159+
// Square output for digest
160+
for(;;) {
161+
int bs = (len < block_size) ? len : block_size;
162+
memcpy(digest, ctx->state, bs);
163+
digest += bs;
164+
len -= bs;
165+
if (!len) break;
166+
permute(ctx);
167+
}
168+
169+
// Zero out context
170+
memset(ctx, 0, sizeof(PHP_SHA3_CTX));
171+
}
172+
173+
// ==========================================================================
174+
175+
#define DECLARE_SHA3_OPS(bits) \
176+
void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
177+
PHP_SHA3_Init(ctx, bits); \
178+
} \
179+
void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
180+
const unsigned char* input, \
181+
unsigned int inputLen) { \
182+
PHP_SHA3_Update(ctx, input, inputLen, \
183+
(1600 - (2 * bits)) >> 3); \
184+
} \
185+
void PHP_SHA3##bits##Final(unsigned char* digest, \
186+
PHP_SHA3_##bits##_CTX* ctx) { \
187+
PHP_SHA3_Final(digest, ctx, \
188+
(1600 - (2 * bits)) >> 3, \
189+
bits >> 3); \
190+
} \
191+
const php_hash_ops php_hash_sha3_##bits##_ops = { \
192+
(php_hash_init_func_t) PHP_SHA3##bits##Init, \
193+
(php_hash_update_func_t) PHP_SHA3##bits##Update, \
194+
(php_hash_final_func_t) PHP_SHA3##bits##Final, \
195+
php_hash_copy, \
196+
bits >> 3, \
197+
(1600 - (2 * bits)) >> 3, \
198+
sizeof(PHP_SHA3_##bits##_CTX) \
199+
}
200+
201+
DECLARE_SHA3_OPS(224);
202+
DECLARE_SHA3_OPS(256);
203+
DECLARE_SHA3_OPS(384);
204+
DECLARE_SHA3_OPS(512);
205+
206+
#undef DECLARE_SHA3_OPS
207+
208+
/*
209+
* Local variables:
210+
* tab-width: 4
211+
* c-basic-offset: 4
212+
* End:
213+
* vim600: sw=4 ts=4 fdm=marker
214+
* vim<600: sw=4 ts=4
215+
*/

ext/hash/php_hash.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ extern const php_hash_ops php_hash_sha224_ops;
6868
extern const php_hash_ops php_hash_sha256_ops;
6969
extern const php_hash_ops php_hash_sha384_ops;
7070
extern const php_hash_ops php_hash_sha512_ops;
71+
extern const php_hash_ops php_hash_sha3_224_ops;
72+
extern const php_hash_ops php_hash_sha3_256_ops;
73+
extern const php_hash_ops php_hash_sha3_384_ops;
74+
extern const php_hash_ops php_hash_sha3_512_ops;
7175
extern const php_hash_ops php_hash_ripemd128_ops;
7276
extern const php_hash_ops php_hash_ripemd160_ops;
7377
extern const php_hash_ops php_hash_ripemd256_ops;

ext/hash/php_hash_sha3.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 7 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1997-2015 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Author: Sara Golemon <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#ifndef PHP_HASH_SHA3_H
20+
#define PHP_HASH_SHA3_H
21+
22+
#include "php.h"
23+
#include "ext/hash/php_hash.h"
24+
25+
typedef struct {
26+
unsigned char state[200]; // 5 * 5 * sizeof(uint64)
27+
php_hash_uint32 pos;
28+
} PHP_SHA3_CTX;
29+
30+
typedef PHP_SHA3_CTX PHP_SHA3_224_CTX;
31+
typedef PHP_SHA3_CTX PHP_SHA3_256_CTX;
32+
typedef PHP_SHA3_CTX PHP_SHA3_384_CTX;
33+
typedef PHP_SHA3_CTX PHP_SHA3_512_CTX;
34+
35+
PHP_HASH_API void PHP_SHA3224Init(PHP_SHA3_224_CTX*);
36+
PHP_HASH_API void PHP_SHA3224Update(PHP_SHA3_224_CTX*, const unsigned char*, unsigned int);
37+
PHP_HASH_API void PHP_SAH3224Final(unsigned char[32], PHP_SHA3_224_CTX*);
38+
39+
PHP_HASH_API void PHP_SHA3256Init(PHP_SHA3_256_CTX*);
40+
PHP_HASH_API void PHP_SHA3256Update(PHP_SHA3_256_CTX*, const unsigned char*, unsigned int);
41+
PHP_HASH_API void PHP_SAH3256Final(unsigned char[32], PHP_SHA3_256_CTX*);
42+
43+
PHP_HASH_API void PHP_SHA3384Init(PHP_SHA3_384_CTX*);
44+
PHP_HASH_API void PHP_SHA3384Update(PHP_SHA3_384_CTX*, const unsigned char*, unsigned int);
45+
PHP_HASH_API void PHP_SAH3384Final(unsigned char[32], PHP_SHA3_384_CTX*);
46+
47+
PHP_HASH_API void PHP_SHA3512Init(PHP_SHA3_512_CTX*);
48+
PHP_HASH_API void PHP_SHA3512Update(PHP_SHA3_512_CTX*, const unsigned char*, unsigned int);
49+
PHP_HASH_API void PHP_SAH3512Final(unsigned char[32], PHP_SHA3_512_CTX*);
50+
51+
#endif

ext/hash/tests/hash_algos.phpt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var_dump(hash_algos());
1818
===Done===
1919
--EXPECTF--
2020
*** Testing hash_algos() : basic functionality ***
21-
array(46) {
21+
array(50) {
2222
[%d]=>
2323
string(3) "md2"
2424
[%d]=>
@@ -36,6 +36,14 @@ array(46) {
3636
[%d]=>
3737
string(6) "sha512"
3838
[%d]=>
39+
string(8) "sha3-224"
40+
[%d]=>
41+
string(8) "sha3-256"
42+
[%d]=>
43+
string(8) "sha3-384"
44+
[%d]=>
45+
string(8) "sha3-512"
46+
[%d]=>
3947
string(9) "ripemd128"
4048
[%d]=>
4149
string(9) "ripemd160"

ext/hash/tests/hash_copy_001.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b
5555
string(6) "sha512"
5656
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
5757
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
58+
string(8) "sha3-224"
59+
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
60+
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
61+
string(8) "sha3-256"
62+
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
63+
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
64+
string(8) "sha3-384"
65+
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
66+
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
67+
string(8) "sha3-512"
68+
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
69+
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
5870
string(9) "ripemd128"
5971
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
6072
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
@@ -193,6 +205,18 @@ string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58
193205
string(6) "sha512"
194206
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
195207
string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
208+
string(8) "sha3-224"
209+
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
210+
string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
211+
string(8) "sha3-256"
212+
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
213+
string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
214+
string(8) "sha3-384"
215+
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
216+
string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
217+
string(8) "sha3-512"
218+
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
219+
string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
196220
string(9) "ripemd128"
197221
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
198222
string(32) "f95f5e22b8875ee0c48219ae97f0674b"

0 commit comments

Comments
 (0)