Skip to content

Commit

Permalink
Implement SHA3 hashing algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
sgolemon committed Oct 16, 2015
1 parent fdb1434 commit d244b54
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 3 deletions.
4 changes: 2 additions & 2 deletions ext/hash/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ if test "$PHP_HASH" != "no"; then

EXT_HASH_SOURCES="hash.c hash_md.c hash_sha.c hash_ripemd.c hash_haval.c \
hash_tiger.c hash_gost.c hash_snefru.c hash_whirlpool.c hash_adler32.c \
hash_crc32.c hash_fnv.c hash_joaat.c"
hash_crc32.c hash_fnv.c hash_joaat.c hash_sha3.c"
EXT_HASH_HEADERS="php_hash.h php_hash_md.h php_hash_sha.h php_hash_ripemd.h \
php_hash_haval.h php_hash_tiger.h php_hash_gost.h php_hash_snefru.h \
php_hash_whirlpool.h php_hash_adler32.h php_hash_crc32.h \
php_hash_fnv.h php_hash_joaat.h"
php_hash_fnv.h php_hash_joaat.h php_hash_sha3.h"

PHP_NEW_EXTENSION(hash, $EXT_HASH_SOURCES, $ext_shared)
ifdef([PHP_INSTALL_HEADERS], [
Expand Down
4 changes: 4 additions & 0 deletions ext/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,10 @@ PHP_MINIT_FUNCTION(hash)
php_hash_register_algo("sha256", &php_hash_sha256_ops);
php_hash_register_algo("sha384", &php_hash_sha384_ops);
php_hash_register_algo("sha512", &php_hash_sha512_ops);
php_hash_register_algo("sha3-224", &php_hash_sha3_224_ops);
php_hash_register_algo("sha3-256", &php_hash_sha3_256_ops);
php_hash_register_algo("sha3-384", &php_hash_sha3_384_ops);
php_hash_register_algo("sha3-512", &php_hash_sha3_512_ops);
php_hash_register_algo("ripemd128", &php_hash_ripemd128_ops);
php_hash_register_algo("ripemd160", &php_hash_ripemd160_ops);
php_hash_register_algo("ripemd256", &php_hash_ripemd256_ops);
Expand Down
215 changes: 215 additions & 0 deletions ext/hash/hash_sha3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include "php_hash_sha3.h"

#if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
(defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
# if defined(__LITTLE_ENDIAN__)
# undef WORDS_BIGENDIAN
# else
# if defined(__BIG_ENDIAN__)
# define WORDS_BIGENDIAN
# endif
# endif
#endif

inline php_hash_uint64 rol64(php_hash_uint64 v, unsigned char b) {
return (v << b) | (v >> (64 - b));
}
inline unsigned char idx(unsigned char x, unsigned char y) {
return x + (5 * y);
}

#ifdef WORDS_BIGENDIAN
inline php_hash_uint64 load64(const unsigned char* x) {
php_hash_uint64 ret = 0;
for (unsigned char i = 7; i >= 0; --i) {
ret <<= 8;
ret |= x[i];
}
return ret;
}
inline void store64(const unsigned char* x, php_hash_uint64 val) {
for (unsigned char i = 0; i < 8; ++i) {
x[i] = val & 0xFF;
val >>= 8;
}
}
inline void xor64(const unsigned char* x, php_hash_uint64 val) {
for (unsigned char i = 0; i < 8; ++i) {
x[i] ^= val & 0xFF;
val >>= 8;
}
}
# define readLane(x, y) load64(ctx->state+sizeof(php_hash_uint64)*idx(x, y))
# define writeLane(x, y, v) store64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
# define XORLane(x, y, v) xor64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
#else
# define readLane(x, y) (((php_hash_uint64*)ctx->state)[idx(x,y)])
# define writeLane(x, y, v) (((php_hash_uint64*)ctx->state)[idx(x,y)] = v)
# define XORLane(x, y, v) (((php_hash_uint64*)ctx->state)[idx(x,y)] ^= v)
#endif

inline char LFSR86540(unsigned char* pLFSR)
{
unsigned char LFSR = *pLFSR;
char result = LFSR & 0x01;
if (LFSR & 0x80) {
// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
LFSR = (LFSR << 1) ^ 0x71;
} else {
LFSR <<= 1;
}
*pLFSR = LFSR;
return result;
}

static void permute(PHP_SHA3_CTX* ctx) {
unsigned char LFSRstate = 0x01;
unsigned char round;

for (round = 0; round < 24; ++round) {
{ // Theta step (see [Keccak Reference, Section 2.3.2])
php_hash_uint64 C[5], D;
unsigned char x, y;
for (x = 0; x < 5; ++x) {
C[x] = readLane(x, 0) ^ readLane(x, 1) ^
readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
}
for (x = 0; x < 5; ++x) {
D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
for (y = 0; y < 5; ++y) {
XORLane(x, y, D);
}
}
}

{ // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
unsigned char x = 1, y = 0, t;
php_hash_uint64 current = readLane(x, y);
for (t = 0; t < 24; ++t) {
unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
unsigned char Y = (2*x + 3*y) % 5;
x = y; y = Y;
php_hash_uint64 temp = readLane(x, y);
writeLane(x, y, rol64(current, r));
current = temp;
}
}

{ // X step (see [Keccak Reference, Section 2.3.1])
unsigned char x, y;
for (y = 0; y < 5; ++y) {
php_hash_uint64 temp[5];
for (x = 0; x < 5; ++x) {
temp[x] = readLane(x, y);
}
for (x = 0; x < 5; ++x) {
writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
}
}
}

{ // i step (see [Keccak Reference, Section 2.3.5])
unsigned char j;
for (j = 0; j < 7; ++j) {
if (LFSR86540(&LFSRstate)) {
php_hash_uint64 bitPos = (1<<j) - 1;
XORLane(0, 0, (php_hash_uint64)1 << bitPos);
}
}
}
}
}

// ==========================================================================

static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
int bits) {
memset(ctx, 0, sizeof(PHP_SHA3_CTX));
}

static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
const unsigned char* buf,
unsigned int count,
int block_size) {
while (count > 0) {
int len = block_size - ctx->pos;
if (len > count) len = count;
count -= len;
while (len-- > 0) {
ctx->state[ctx->pos++] ^= *(buf++);
}
if (ctx->pos >= block_size) {
permute(ctx);
ctx->pos = 0;
}
}
}

static void PHP_SHA3_Final(unsigned char* digest,
PHP_SHA3_CTX* ctx,
int block_size,
int digest_size) {
int len = digest_size;

// Pad state to finalize
ctx->state[ctx->pos++] ^= 0x06;
ctx->state[block_size-1] ^= 0x80;
permute(ctx);

// Square output for digest
for(;;) {
int bs = (len < block_size) ? len : block_size;
memcpy(digest, ctx->state, bs);
digest += bs;
len -= bs;
if (!len) break;
permute(ctx);
}

// Zero out context
memset(ctx, 0, sizeof(PHP_SHA3_CTX));
}

// ==========================================================================

#define DECLARE_SHA3_OPS(bits) \
void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
PHP_SHA3_Init(ctx, bits); \
} \
void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
const unsigned char* input, \
unsigned int inputLen) { \
PHP_SHA3_Update(ctx, input, inputLen, \
(1600 - (2 * bits)) >> 3); \
} \
void PHP_SHA3##bits##Final(unsigned char* digest, \
PHP_SHA3_##bits##_CTX* ctx) { \
PHP_SHA3_Final(digest, ctx, \
(1600 - (2 * bits)) >> 3, \
bits >> 3); \
} \
const php_hash_ops php_hash_sha3_##bits##_ops = { \
(php_hash_init_func_t) PHP_SHA3##bits##Init, \
(php_hash_update_func_t) PHP_SHA3##bits##Update, \
(php_hash_final_func_t) PHP_SHA3##bits##Final, \
php_hash_copy, \
bits >> 3, \
(1600 - (2 * bits)) >> 3, \
sizeof(PHP_SHA3_##bits##_CTX) \
}

DECLARE_SHA3_OPS(224);
DECLARE_SHA3_OPS(256);
DECLARE_SHA3_OPS(384);
DECLARE_SHA3_OPS(512);

#undef DECLARE_SHA3_OPS

/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/
4 changes: 4 additions & 0 deletions ext/hash/php_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ extern const php_hash_ops php_hash_sha224_ops;
extern const php_hash_ops php_hash_sha256_ops;
extern const php_hash_ops php_hash_sha384_ops;
extern const php_hash_ops php_hash_sha512_ops;
extern const php_hash_ops php_hash_sha3_224_ops;
extern const php_hash_ops php_hash_sha3_256_ops;
extern const php_hash_ops php_hash_sha3_384_ops;
extern const php_hash_ops php_hash_sha3_512_ops;
extern const php_hash_ops php_hash_ripemd128_ops;
extern const php_hash_ops php_hash_ripemd160_ops;
extern const php_hash_ops php_hash_ripemd256_ops;
Expand Down
51 changes: 51 additions & 0 deletions ext/hash/php_hash_sha3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2015 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/

#ifndef PHP_HASH_SHA3_H
#define PHP_HASH_SHA3_H

#include "php.h"
#include "ext/hash/php_hash.h"

typedef struct {
unsigned char state[200]; // 5 * 5 * sizeof(uint64)
php_hash_uint32 pos;
} PHP_SHA3_CTX;

typedef PHP_SHA3_CTX PHP_SHA3_224_CTX;
typedef PHP_SHA3_CTX PHP_SHA3_256_CTX;
typedef PHP_SHA3_CTX PHP_SHA3_384_CTX;
typedef PHP_SHA3_CTX PHP_SHA3_512_CTX;

PHP_HASH_API void PHP_SHA3224Init(PHP_SHA3_224_CTX*);
PHP_HASH_API void PHP_SHA3224Update(PHP_SHA3_224_CTX*, const unsigned char*, unsigned int);
PHP_HASH_API void PHP_SAH3224Final(unsigned char[32], PHP_SHA3_224_CTX*);

PHP_HASH_API void PHP_SHA3256Init(PHP_SHA3_256_CTX*);
PHP_HASH_API void PHP_SHA3256Update(PHP_SHA3_256_CTX*, const unsigned char*, unsigned int);
PHP_HASH_API void PHP_SAH3256Final(unsigned char[32], PHP_SHA3_256_CTX*);

PHP_HASH_API void PHP_SHA3384Init(PHP_SHA3_384_CTX*);
PHP_HASH_API void PHP_SHA3384Update(PHP_SHA3_384_CTX*, const unsigned char*, unsigned int);
PHP_HASH_API void PHP_SAH3384Final(unsigned char[32], PHP_SHA3_384_CTX*);

PHP_HASH_API void PHP_SHA3512Init(PHP_SHA3_512_CTX*);
PHP_HASH_API void PHP_SHA3512Update(PHP_SHA3_512_CTX*, const unsigned char*, unsigned int);
PHP_HASH_API void PHP_SAH3512Final(unsigned char[32], PHP_SHA3_512_CTX*);

#endif
10 changes: 9 additions & 1 deletion ext/hash/tests/hash_algos.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var_dump(hash_algos());
===Done===
--EXPECTF--
*** Testing hash_algos() : basic functionality ***
array(46) {
array(50) {
[%d]=>
string(3) "md2"
[%d]=>
Expand All @@ -36,6 +36,14 @@ array(46) {
[%d]=>
string(6) "sha512"
[%d]=>
string(8) "sha3-224"
[%d]=>
string(8) "sha3-256"
[%d]=>
string(8) "sha3-384"
[%d]=>
string(8) "sha3-512"
[%d]=>
string(9) "ripemd128"
[%d]=>
string(9) "ripemd160"
Expand Down
24 changes: 24 additions & 0 deletions ext/hash/tests/hash_copy_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b
string(6) "sha512"
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
string(8) "sha3-224"
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
string(8) "sha3-256"
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
string(8) "sha3-384"
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
string(8) "sha3-512"
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
string(9) "ripemd128"
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
Expand Down Expand Up @@ -193,6 +205,18 @@ string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58
string(6) "sha512"
string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
string(8) "sha3-224"
string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
string(8) "sha3-256"
string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
string(8) "sha3-384"
string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
string(8) "sha3-512"
string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
string(9) "ripemd128"
string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
string(32) "f95f5e22b8875ee0c48219ae97f0674b"
Expand Down
Loading

0 comments on commit d244b54

Please sign in to comment.