123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) 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: |
- | https://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> |
- +----------------------------------------------------------------------+
- */
- #include "php_hash.h"
- #include "php_hash_sha3.h"
- #ifdef HAVE_SLOW_HASH3
- // ================= slow algo ==============================================
- #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
- static inline uint64_t rol64(uint64_t v, unsigned char b) {
- return (v << b) | (v >> (64 - b));
- }
- static inline unsigned char idx(unsigned char x, unsigned char y) {
- return x + (5 * y);
- }
- #ifdef WORDS_BIGENDIAN
- static inline uint64_t load64(const unsigned char* x) {
- signed char i;
- uint64_t ret = 0;
- for (i = 7; i >= 0; --i) {
- ret <<= 8;
- ret |= x[i];
- }
- return ret;
- }
- static inline void store64(unsigned char* x, uint64_t val) {
- size_t i;
- for (i = 0; i < 8; ++i) {
- x[i] = val & 0xFF;
- val >>= 8;
- }
- }
- static inline void xor64(unsigned char* x, uint64_t val) {
- size_t i;
- for (i = 0; i < 8; ++i) {
- x[i] ^= val & 0xFF;
- val >>= 8;
- }
- }
- # define readLane(x, y) load64(ctx->state+sizeof(uint64_t)*idx(x, y))
- # define writeLane(x, y, v) store64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
- # define XORLane(x, y, v) xor64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
- #else
- # define readLane(x, y) (((uint64_t*)ctx->state)[idx(x,y)])
- # define writeLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] = v)
- # define XORLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] ^= v)
- #endif
- static 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])
- uint64_t 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;
- uint64_t 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;
- uint64_t temp;
- x = y;
- y = Y;
- 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) {
- uint64_t 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)) {
- uint64_t bitPos = (1<<j) - 1;
- XORLane(0, 0, (uint64_t)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,
- size_t count,
- size_t block_size) {
- while (count > 0) {
- size_t 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,
- size_t block_size,
- size_t digest_size) {
- size_t 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
- ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
- }
- static int php_sha3_unserialize(php_hashcontext_object *hash,
- zend_long magic,
- const zval *zv,
- size_t block_size)
- {
- PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context;
- int r = FAILURE;
- if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
- && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == SUCCESS
- && ctx->pos < block_size) {
- return SUCCESS;
- } else {
- return r != SUCCESS ? r : -2000;
- }
- }
- // ==========================================================================
- #define DECLARE_SHA3_OPS(bits) \
- void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
- PHP_SHA3_Init(ctx, bits); \
- } \
- void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
- const unsigned char* input, \
- size_t 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); \
- } \
- static int php_sha3##bits##_unserialize(php_hashcontext_object *hash, \
- zend_long magic, \
- const zval *zv) { \
- return php_sha3_unserialize(hash, magic, zv, (1600 - (2 * bits)) >> 3); \
- } \
- const php_hash_ops php_hash_sha3_##bits##_ops = { \
- "sha3-" #bits, \
- (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, \
- php_hash_serialize, \
- php_sha3##bits##_unserialize, \
- PHP_SHA3_SPEC, \
- bits >> 3, \
- (1600 - (2 * bits)) >> 3, \
- sizeof(PHP_SHA3_##bits##_CTX), \
- 1 \
- }
- #else
- // ================= fast algo ==============================================
- #define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
- #include "KeccakHash.h"
- /* KECCAK SERIALIZATION
- Keccak_HashInstance consists of:
- KeccakWidth1600_SpongeInstance {
- unsigned char state[200];
- unsigned int rate; -- fixed for digest size
- unsigned int byteIOIndex; -- in range [0, rate/8)
- int squeezing; -- 0 normally, 1 only during finalize
- } sponge;
- unsigned int fixedOutputLength; -- fixed for digest size
- unsigned char delimitedSuffix; -- fixed for digest size
- NB If the external sha3/ library is updated, the serialization code
- may need to be updated.
- The simpler SHA3 code's serialization states are not interchangeable with
- Keccak. Furthermore, the Keccak sponge state is sensitive to architecture
- -- 32-bit and 64-bit implementations produce different states. It does not
- appear that the state is sensitive to endianness. */
- #if Keccak_HashInstance_ImplType == 64
- /* corresponds to sha3/generic64lc */
- # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 100
- #elif Keccak_HashInstance_ImplType == 32
- /* corresponds to sha3/generic32lc */
- # define PHP_HASH_SERIALIZE_MAGIC_KECCAK 101
- #else
- # error "Unknown Keccak_HashInstance_ImplType"
- #endif
- #define PHP_KECCAK_SPEC "b200IiIIB"
- static int php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv)
- {
- *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
- return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC);
- }
- static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
- {
- Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
- int r = FAILURE;
- if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK
- && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == SUCCESS
- && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
- return SUCCESS;
- } else {
- return r != SUCCESS ? r : -2000;
- }
- }
- // ==========================================================================
- #define DECLARE_SHA3_OPS(bits) \
- void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
- ZEND_ASSERT(sizeof(Keccak_HashInstance) <= sizeof(PHP_SHA3_##bits##_CTX)); \
- Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx); \
- } \
- void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
- const unsigned char* input, \
- size_t inputLen) { \
- Keccak_HashUpdate((Keccak_HashInstance *)ctx, input, inputLen * 8); \
- } \
- void PHP_SHA3##bits##Final(unsigned char* digest, \
- PHP_SHA3_##bits##_CTX* ctx) { \
- Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \
- } \
- const php_hash_ops php_hash_sha3_##bits##_ops = { \
- "sha3-" #bits, \
- (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, \
- php_keccak_serialize, \
- php_keccak_unserialize, \
- PHP_KECCAK_SPEC, \
- bits >> 3, \
- (1600 - (2 * bits)) >> 3, \
- sizeof(PHP_SHA3_CTX), \
- 1 \
- }
- #endif
- // ================= both algo ==============================================
- DECLARE_SHA3_OPS(224);
- DECLARE_SHA3_OPS(256);
- DECLARE_SHA3_OPS(384);
- DECLARE_SHA3_OPS(512);
- #undef DECLARE_SHA3_OPS
|