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 } };