Package: libapache2-mod-auth-mysql
Severity: wishlist
Version: 4.3.9-13.1
Tags: patch

One implementation of Phpass support for mod_auth_mysql.

Phpass password hashing is described here:
http://www.openwall.com/phpass/ <http://www.openwall.com/phpass/>

Some info related to the patch is here:
http://stackoverflow.com/q/12543883/1148030 
<http://stackoverflow.com/q/12543883/1148030>

I have also submitted the patch to sourceforge upstream:
https://sourceforge.net/tracker/?func=detail&aid=3572669&group_id=60218&atid=493464


Peter

diff --git a/DIRECTIVES b/DIRECTIVES
index 293fab4..c76fd80 100644
--- a/DIRECTIVES
+++ b/DIRECTIVES
@@ -210,7 +210,21 @@ Auth_MySQL_Encryption_Types <type_list>
 	Apache
 		The hashing scheme used by htpasswd utility. Compatible to
 		authuserfile.
-		
+               
+    PHPass
+        Portable PHP password hashing framework
+        http://www.openwall.com/phpass/
+        
+        PHPass is a public domain password hashing scheme used 
+        by some PHP-based software (eg. Wordpress 3, phpBB3).
+        It is similar in spirit to a more common bcrypt for C
+        applications, but PHPass can be implemented in pure PHP using
+        only primitives that are available in all PHP versions.
+
+        The basic idea is that the number of iterations of
+        the cryptographic primitive can scale to match
+        the increases in computing power.
+
 Auth_MySQL_Encrypted_Passwords <on/off> (DEPRECATED)
 	Equivalent to: Auth_MySQL_Encryption_Types Crypt_DES
 	Only used if ...Encryption_Types is not set.  Defaults to 'on'.  If
diff --git a/mod_auth_mysql.c b/mod_auth_mysql.c
index da3ead0..9a55973 100644
--- a/mod_auth_mysql.c
+++ b/mod_auth_mysql.c
@@ -105,6 +105,7 @@ unsigned long auth_db_client_flag = 0;
 #endif
 #define SHA1SUM_ENCRYPTION_FLAG		1<<6
 #define APACHE_ENCRYPTION_FLAG		1<<7
+#define PHPASS_ENCRYPTION_FLAG		1<<8
 
 /* from include/sha1.h from the mysql-server source distribution */
 #define SHA1_HASH_SIZE 20 /* Hash size in bytes */
@@ -250,6 +251,91 @@ static int check_apache_encryption(const char *passwd, char *enc_passwd)
 #endif
 }
 
+static int check_phpass_encryption(const char *passwd, char *enc_passwd)
+{
+#ifdef APACHE2
+	char hash[APR_MD5_DIGESTSIZE];
+	apr_md5_ctx_t ct;
+#else
+	char hash[AP_MD5_DIGESTSIZE];
+	AP_MD5_CTX ct;
+#endif
+	int iterations;
+	int iteration;
+
+	char encoded_hash[22];
+	int i;
+	char *base64_digits =
+		"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+	int high_index;
+	unsigned char high, low;
+	int value;
+
+	if (strlen(enc_passwd) < 4 + 8 + 22) {
+		return 0; /* too short for PHPass. */
+	}
+
+	if (!strncmp(enc_passwd, "*0", 2)) {
+		return 0; /* disabled password */
+	}
+
+	/* PHPass uses "$P$", phpBB3 uses "$H$" as identifier */
+	if (strncmp(enc_passwd, "$P$", 3) && strncmp(enc_passwd, "$H$", 3)) {
+		return 0;
+	}
+
+	if (enc_passwd[3] >= '5' && enc_passwd[3] <= '9') {
+		iterations = 1 << ((enc_passwd[3] - '5') + 7);
+	} else if (enc_passwd[3] >= 'A' && enc_passwd[3] <= 'S') {
+		iterations = 1 << ((enc_passwd[3] - 'A') + 12);
+	} else {
+		return 0; /* invalid iteration count */
+	}
+
+#ifdef APACHE2
+	apr_md5_init(&ct);
+	apr_md5_update(&ct, &enc_passwd[4], 8); /* salt */
+	apr_md5_update(&ct, passwd, strlen(passwd));
+	apr_md5_final(hash, &ct);
+#else
+	ap_MD5Init(&ct);
+	ap_MD5Update(&ct, &enc_passwd[4], 8); /* salt */
+	ap_MD5Update(&ct, passwd, strlen(passwd));
+	ap_MD5Final(hash, &ct);
+#endif
+
+	for (iteration = 0; iteration < iterations; iteration++)
+	{
+#ifdef APACHE2
+		apr_md5_init(&ct);
+		apr_md5_update(&ct, hash, APR_MD5_DIGESTSIZE);
+		apr_md5_update(&ct, passwd, strlen(passwd));
+		apr_md5_final(hash, &ct);
+#else
+		ap_MD5Init(&ct);
+		ap_MD5Update(&ct, hash, AP_MD5_DIGESTSIZE);
+		ap_MD5Update(&ct, passwd, strlen(passwd));
+		ap_MD5Final(hash, &ct);
+#endif
+	}
+
+	/* PHPass uses a variant of base64 encoding where the input bits
+	   are processed in different order and no padding is used. */
+	for (i = 0; i < sizeof(encoded_hash); i++)
+	{
+		high_index = (i / 4) * 3 + (i % 4);
+		low = (i % 4 != 0) ? (unsigned char) hash[high_index - 1] : 0;
+		high = (i % 4 != 3 && high_index < sizeof(hash))
+			? (unsigned char) hash[high_index] : 0;
+
+		value = ( (high << (2 * (i % 4))) | (low >> (8 - 2 * (i % 4))) ) & 0x3f;
+
+		encoded_hash[i] = base64_digits[value];
+	}
+
+	return (!strncmp(encoded_hash, &enc_passwd[4 + 8], sizeof(encoded_hash)));
+}
+
 typedef struct {
 	char *name;
 	int (*check_function)(const char *passwd, char *enc_passwd);
@@ -269,6 +355,7 @@ encryption_type_entry supported_encryption_types[] = {
 	{ "PHP_MD5",		check_PHP_MD5_encryption,		PHP_MD5_ENCRYPTION_FLAG	},
 	{ "SHA1Sum",	check_SHA1Sum_encryption, SHA1SUM_ENCRYPTION_FLAG},
 	{ "Apache",		check_apache_encryption,		APACHE_ENCRYPTION_FLAG  },
+	{ "PHPass",		check_phpass_encryption,		PHPASS_ENCRYPTION_FLAG  },
 	/* add additional encryption types below */
 	{ NULL,			NULL,					0 }
 };

Reply via email to