Fix Bug #75284 sha3 is not supported on bigendian machine

This commit is contained in:
Remi Collet 2017-09-29 14:38:21 +02:00 committed by Remi Collet
parent a1c0824518
commit d67873ec99
3 changed files with 239 additions and 12 deletions

View File

@ -25,24 +25,32 @@ if test "$PHP_HASH" != "no"; then
AC_CHECK_SIZEOF(long, 4)
AC_CHECK_SIZEOF(long long, 8)
PHP_CHECK_64BIT([
SHA3_DIR="sha3/generic32lc"
SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-inplace32BI.c"
],[
SHA3_DIR="sha3/generic64lc"
SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-opt64.c"
])
EXT_HASH_SHA3_SOURCES="$SHA3_OPT_SRC $SHA3_DIR/KeccakHash.c $SHA3_DIR/KeccakSponge.c"
PHP_HASH_CFLAGS="-I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded"
if test $ac_cv_c_bigendian_php = yes; then
EXT_HASH_SHA3_SOURCES="hash_sha3.c"
AC_DEFINE(HAVE_SLOW_HASH3, 1, [Define is hash3 algo is available])
AC_MSG_WARN("Use SHA3 slow implementation on bigendian")
else
PHP_CHECK_64BIT([
SHA3_DIR="sha3/generic32lc"
SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-inplace32BI.c"
],[
SHA3_DIR="sha3/generic64lc"
SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-opt64.c"
])
EXT_HASH_SHA3_SOURCES="$SHA3_OPT_SRC $SHA3_DIR/KeccakHash.c $SHA3_DIR/KeccakSponge.c hash_sha3.c"
PHP_HASH_CFLAGS="-I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded"
PHP_ADD_BUILD_DIR(ext/hash/$SHA3_DIR, 1)
fi
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_sha3.c $EXT_HASH_SHA3_SOURCES"
hash_crc32.c hash_fnv.c hash_joaat.c $EXT_HASH_SHA3_SOURCES"
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_sha3.h"
PHP_ADD_BUILD_DIR(ext/hash/$SHA3_DIR, 1)
PHP_NEW_EXTENSION(hash, $EXT_HASH_SOURCES, $ext_shared,,$PHP_HASH_CFLAGS)
ifdef([PHP_INSTALL_HEADERS], [
PHP_INSTALL_HEADERS(ext/hash, $EXT_HASH_HEADERS)

View File

@ -19,6 +19,217 @@
#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) {
char i;
for (i = 0; i < 8; ++i) {
x[i] = val & 0xFF;
val >>= 8;
}
}
static inline void xor64(unsigned char* x, uint64_t val) {
char 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,
unsigned int count,
size_t block_size) {
while (count > 0) {
unsigned 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), \
1 \
}
#else
// ================= fast algo ==============================================
#define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
#include "KeccakHash.h"
@ -60,6 +271,9 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \
1 \
}
#endif
// ================= both algo ==============================================
DECLARE_SHA3_OPS(224);
DECLARE_SHA3_OPS(256);
DECLARE_SHA3_OPS(384);

View File

@ -22,7 +22,12 @@
#include "php.h"
typedef struct {
#ifdef HAVE_SLOW_HASH3
unsigned char state[200]; // 5 * 5 * sizeof(uint64)
uint32_t pos;
#else
void *hashinstance;
#endif
} PHP_SHA3_CTX;
typedef PHP_SHA3_CTX PHP_SHA3_224_CTX;