I’m working on an implementation of PHPass for Google Apps Script but am struggling with the Portable Hashes variable MD5 iterations.
The reason we’re doing this is that we need to be able to automate regular password changes for a large number of WordPress sites. We need to generate hashes that can be inserted directly into the database. Therefore our implementation needs to be 100% compatible with the WordPress implementation of portable hashes (per wp-includes/class-phpass.php).
The crux of the issue lies in the MD5 iterations; computeDigest returns Byte[]
whereas the input requires a String
so the following code gives undesirable results as regards compatibility with PHPass:
function genHash_(passwd,settings) {
var output = '';
var salt = settings.slice(4,12);
var count = 1 << itoa64_.indexOf(settings[3]);
var hash = genMD5_(bin2String_(salt) + passwd);
do {
hash = genMD5_(bin2String(hash) + passwd);
} while (--count);
output = settings.slice(0,12);
output += encode64_(hash,16);
return output;
}
function genMD5_(input) {
return Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, input);
}
function bin2String_(bin) {
return String.fromCharCode.apply(String,bin);
}
In the PHP implementation (from wp-includes/class-phpass.php):
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
The TRUE
causes md5
to return the result in a raw binary format. PHP Strings are 100% binary compatible so this ‘just works’.
The problem with an Apps Script implementation appears to be that, however you dice it, the conversion to string from the output of computeDigest doesn’t work. Even if you stuff a String using fromCharCode
to get the hash, the converting back again with getCharAt
yields different results thanks to the unicode conversions.
So I’ve more or less concluded that this is a limitation of computeDigest and would therefore require a change from Google. But on the off chance that someone has any ideas, I think it’s worth asking the question.
Edit: It’s been mentioned that this could be a duplicate of another question that relates to converting the output of computeDigest
into a string. While this is similar, it’s not a duplicate because the solution requires binary compatibility between the output and input of computeDigest.
Edit: I’ve looked at an approach using Blob.getDataAsString()
suggested in this question but this suffers from a similar problem at the point of conversion.