carlwgeorge / rpms / php

Forked from rpms/php 4 years ago
Clone
Blob Blame History Raw
From d3ff2d35daab910198d505be20ddad0587026cb7 Mon Sep 17 00:00:00 2001
From: Remi Collet <remi@remirepo.net>
Date: Fri, 29 Sep 2017 14:38:21 +0200
Subject: [PATCH] Fix Bug #75284 sha3 is not supported on bigendian machine

---
 ext/hash/config.m4       |  32 ++++---
 ext/hash/hash_sha3.c     | 214 +++++++++++++++++++++++++++++++++++++++++++++++
 ext/hash/php_hash_sha3.h |   5 ++
 3 files changed, 239 insertions(+), 12 deletions(-)

diff --git a/ext/hash/config.m4 b/ext/hash/config.m4
index 66cc7ca8108f..932e6d6f22c6 100644
--- a/ext/hash/config.m4
+++ b/ext/hash/config.m4
@@ -24,25 +24,33 @@ if test "$PHP_HASH" != "no"; then
   AC_CHECK_SIZEOF(int, 4)
   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)
diff --git a/ext/hash/hash_sha3.c b/ext/hash/hash_sha3.c
index ee9d010da4b2..98010c535019 100644
--- a/ext/hash/hash_sha3.c
+++ b/ext/hash/hash_sha3.c
@@ -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);
diff --git a/ext/hash/php_hash_sha3.h b/ext/hash/php_hash_sha3.h
index b47d1b102f37..73f0f8af3662 100644
--- a/ext/hash/php_hash_sha3.h
+++ b/ext/hash/php_hash_sha3.h
@@ -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;