From: Sara Golemon Date: Fri, 16 Oct 2015 02:13:04 +0000 (-0700) Subject: Implement SHA3 hashing algorithm X-Git-Tag: php-7.1.0alpha1~959 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d244b54c67cc2725283b78d4bb128501ae7910d3;p=php Implement SHA3 hashing algorithm --- diff --git a/ext/hash/config.m4 b/ext/hash/config.m4 index 5174db3b71..703cf14a30 100644 --- a/ext/hash/config.m4 +++ b/ext/hash/config.m4 @@ -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], [ diff --git a/ext/hash/hash.c b/ext/hash/hash.c index c1a94c2d09..cc94fb220d 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -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); diff --git a/ext/hash/hash_sha3.c b/ext/hash/hash_sha3.c new file mode 100644 index 0000000000..2fb24b316b --- /dev/null +++ b/ext/hash/hash_sha3.c @@ -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< 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 + */ diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h index c8104710ba..2156116696 100644 --- a/ext/hash/php_hash.h +++ b/ext/hash/php_hash.h @@ -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; diff --git a/ext/hash/php_hash_sha3.h b/ext/hash/php_hash_sha3.h new file mode 100644 index 0000000000..65196ab7f1 --- /dev/null +++ b/ext/hash/php_hash_sha3.h @@ -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 | + +----------------------------------------------------------------------+ +*/ + +#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 diff --git a/ext/hash/tests/hash_algos.phpt b/ext/hash/tests/hash_algos.phpt index f2d6fc3ffb..ca1dcad456 100644 --- a/ext/hash/tests/hash_algos.phpt +++ b/ext/hash/tests/hash_algos.phpt @@ -18,7 +18,7 @@ var_dump(hash_algos()); ===Done=== --EXPECTF-- *** Testing hash_algos() : basic functionality *** -array(46) { +array(50) { [%d]=> string(3) "md2" [%d]=> @@ -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" diff --git a/ext/hash/tests/hash_copy_001.phpt b/ext/hash/tests/hash_copy_001.phpt index f9fe7cc552..67d16aaf88 100644 --- a/ext/hash/tests/hash_copy_001.phpt +++ b/ext/hash/tests/hash_copy_001.phpt @@ -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" @@ -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" diff --git a/ext/hash/tests/sha3.phpt b/ext/hash/tests/sha3.phpt new file mode 100644 index 0000000000..67fb22f988 --- /dev/null +++ b/ext/hash/tests/sha3.phpt @@ -0,0 +1,56 @@ +--TEST-- +sha3 algorithm +--SKIPIF-- + +--FILE-- +