[PHP-users 28625] Re: MD5の仕組みについて

Seiji Masugata s.masugata @ digicom.dnp.co.jp
2006年 3月 6日 (月) 09:16:47 JST


こんにちわ、桝形です。

> 気になる場合はPHP5を使ってSHA1にするとコリージョンの可能性は大幅に減少
> します。MD5は128bit, SHA1は160bitの強度です。PHP5ならSHA1はデフォルトで
> 利用可能なのでわざわざ強度の弱いハッシュ関数を利用する必要はないのでSHA1
> を利用するべきです。

PHP4でもSHA1を利用できると嬉しい(かもしれない)ので、PHP5から
移植してみました。既に何処かにあったら(ごみレス)スミマセン。

事前に「php-4.4.2-strict-session.patch」を当ててから、パッチを
当てて下さい。

http://wiki.ohgaki.net/index.php?PHP%2Fpatch%2FStrictSession

---------------------------------------------------------------------
--- php-4.4.2/ext/session/php_session.h,orig	2006-02-02 18:09:37.000000000 +0900
+++ php-4.4.2/ext/session/php_session.h	2006-03-06 08:48:07.000000000 +0900
@@ -126,6 +126,8 @@
 	zend_bool use_trans_sid;	/* contains the INI value of whether to use trans-sid */
 	zend_bool apply_trans_sid;	/* whether or not to enable trans-sid for the current request */
 	zend_bool use_strict_mode;      /* whether or not PHP accepts unknown session ids */
+	long hash_func;
+	long hash_bits_per_character;
 	int send_cookie;
 	int define_sid;
 } php_ps_globals;
--- php-4.4.2/ext/session/session.c,orig	2006-02-02 18:09:37.000000000 +0900
+++ php-4.4.2/ext/session/session.c	2006-03-06 08:48:07.000000000 +0900
@@ -38,6 +38,7 @@
 #include "SAPI.h"
 #include "php_session.h"
 #include "ext/standard/md5.h"
+#include "ext/standard/sha1.h"
 #include "ext/standard/php_var.h"
 #include "ext/standard/datetime.h"
 #include "ext/standard/php_lcg.h"
@@ -162,6 +163,8 @@
 	STD_PHP_INI_ENTRY("session.cache_limiter",      "nocache",   PHP_INI_ALL, OnUpdateString, cache_limiter,      php_ps_globals,    ps_globals)
 	STD_PHP_INI_ENTRY("session.cache_expire",       "180",       PHP_INI_ALL, OnUpdateInt,    cache_expire,       php_ps_globals,    ps_globals)
 	STD_PHP_INI_BOOLEAN("session.use_trans_sid",    "0",         PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool,   use_trans_sid,      php_ps_globals,    ps_globals)
+	STD_PHP_INI_ENTRY("session.hash_function",      "0",         PHP_INI_ALL, OnUpdateInt,    hash_func,          php_ps_globals,    ps_globals)
+	STD_PHP_INI_ENTRY("session.hash_bits_per_character",      "4",         PHP_INI_ALL, OnUpdateInt,    hash_bits_per_character,          php_ps_globals,    ps_globals)
 
 	/* Commented out until future discussion */
 	/* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
@@ -571,55 +574,150 @@
 	}
 }
 
-static char hexconvtab[] = "0123456789abcdef";
+/*
+ * Note that we cannot use the BASE64 alphabet here, because
+ * it contains "/" and "+": both are unacceptable for simple inclusion
+ * into URLs.
+ */
+
+static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
+
+enum {
+	PS_HASH_FUNC_MD5,
+	PS_HASH_FUNC_SHA1
+};
+
+/* returns a pointer to the byte after the last valid character in out */
+static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits)
+{
+	unsigned char *p, *q;
+	unsigned short w;
+	int mask;
+	int have;
+	
+	p = in;
+	q = in + inlen;
+
+	w = 0;
+	have = 0;
+	mask = (1 << nbits) - 1;
+	
+	while (1) {
+		if (have < nbits) {
+			if (p < q) {
+				w |= *p++ << have;
+				have += 8;
+			} else {
+				/* consumed everything? */
+				if (have == 0) break;
+				/* No? We need a final round */
+				have = nbits;
+			}
+		}
+
+		/* consume nbits */
+		*out++ = hexconvtab[w & mask];
+		w >>= nbits;
+		have -= nbits;
+	}
+	
+	*out = '\0';
+	return out;
+}
 
 char *php_session_create_id(PS_CREATE_SID_ARGS)
 {
-	PHP_MD5_CTX context;
-	unsigned char digest[16];
-	char buf[256];
+	PHP_MD5_CTX md5_context;
+	PHP_SHA1_CTX sha1_context;
+	unsigned char digest[21];
+	int digest_len;
+	int j;
+	char *buf;
 	struct timeval tv;
-	int i;
-	int j = 0;
-	unsigned char c;
+	zval **array;
+	zval **token;
+	char *remote_addr = NULL;
 
 	gettimeofday(&tv, NULL);
-	PHP_MD5Init(&context);
 	
-	sprintf(buf, "%ld%ld%0.8f", tv.tv_sec, tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
-	PHP_MD5Update(&context, buf, strlen(buf));
+	if (zend_hash_find(&EG(symbol_table), "_SERVER",
+				sizeof("_SERVER"), (void **) &array) == SUCCESS &&
+			Z_TYPE_PP(array) == IS_ARRAY &&
+			zend_hash_find(Z_ARRVAL_PP(array), "REMOTE_ADDR",
+				sizeof("REMOTE_ADDR"), (void **) &token) == SUCCESS) {
+		remote_addr = Z_STRVAL_PP(token);
+	}
+
+	buf = emalloc(100);
+
+	/* maximum 15+19+19+10 bytes */	
+	sprintf(buf, "%.15s%ld%ld%0.8f", remote_addr ? remote_addr : "", 
+			tv.tv_sec, tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
+
+	switch (PS(hash_func)) {
+	case PS_HASH_FUNC_MD5:
+		PHP_MD5Init(&md5_context);
+		PHP_MD5Update(&md5_context, buf, strlen(buf));
+		digest_len = 16;
+		break;
+	case PS_HASH_FUNC_SHA1:
+		PHP_SHA1Init(&sha1_context);
+		PHP_SHA1Update(&sha1_context, buf, strlen(buf));
+		digest_len = 20;
+		break;
+	default:
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
+		efree(buf);
+		return NULL;
+	}
 
 	if (PS(entropy_length) > 0) {
 		int fd;
 
 		fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);
 		if (fd >= 0) {
-			unsigned char buf[2048];
+			unsigned char rbuf[2048];
 			int n;
 			int to_read = PS(entropy_length);
 			
 			while (to_read > 0) {
-				n = read(fd, buf, MIN(to_read, sizeof(buf)));
+				n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));
 				if (n <= 0) break;
-				PHP_MD5Update(&context, buf, n);
+				
+				switch (PS(hash_func)) {
+				case PS_HASH_FUNC_MD5:
+					PHP_MD5Update(&md5_context, rbuf, n);
+					break;
+				case PS_HASH_FUNC_SHA1:
+					PHP_SHA1Update(&sha1_context, rbuf, n);
+					break;
+				}
 				to_read -= n;
 			}
 			close(fd);
 		}
 	}
 
-	PHP_MD5Final(digest, &context);
-	
-	for (i = 0; i < 16; i++) {
-		c = digest[i];
-		buf[j++] = hexconvtab[c >> 4];
-		buf[j++] = hexconvtab[c & 15];
+	switch (PS(hash_func)) {
+	case PS_HASH_FUNC_MD5:
+		PHP_MD5Final(digest, &md5_context);
+		break;
+	case PS_HASH_FUNC_SHA1:
+		PHP_SHA1Final(digest, &sha1_context);
+		break;
+	}
+
+	if (PS(hash_bits_per_character) < 4
+			|| PS(hash_bits_per_character) > 6) {
+		PS(hash_bits_per_character) = 4;
+
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now");
 	}
-	buf[j] = '\0';
+	j = (int) (bin_to_readable(digest, digest_len, buf, PS(hash_bits_per_character)) - buf);
 	
 	if (newlen) 
 		*newlen = j;
-	return estrdup(buf);
+	return buf;
 }
 
 static void php_session_initialize(TSRMLS_D)
---------------------------------------------------------------------

php.iniに以下のエントリを追加して、Webサーバ(ソフト)の
再起動を行なって下さい。

--------------------------------------------------------------------
session.use_strict_mode = 1

; Select a hash function
; 0: MD5   (128 bits)
; 1: SHA-1 (160 bits)
session.hash_function = 1

; Define how many bits are stored in each character when converting
; the binary hash data to something readable.
;
; 4 bits: 0-9, a-f
; 5 bits: 0-9, a-v
; 6 bits: 0-9, a-z, A-Z, "-", ","
session.hash_bits_per_character = 5
--------------------------------------------------------------------

-- 
Seiji Masugata <s.masugata @ digicom.dnp.co.jp>



PHP-users メーリングリストの案内