Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ircmaxell/ac0710ce044504f65cf0 to your computer and use it in GitHub Desktop.
Save ircmaxell/ac0710ce044504f65cf0 to your computer and use it in GitHub Desktop.
A polyfill for PHP bug https://bugs.php.net/bug.php?id=62372
<?php
define('CRYPT_SALT_LEN_MAX', 16);
define('CRYPT_ROUNDS_DEFAULT', 5000);
/**
* A PHP shim for crypt sha256 and sha512
* to workaround bug 62372
* @see https://bugs.php.net/bug.php?id=62372
*/
function crypt_sha($password, $salt) {
if (!in_array(substr($salt, 0, 3), array('$5$', '$6$'))) return false;
$algo = $salt[1] === '5' ? 'sha256' : 'sha512';
$padLen = $salt[1] === '5' ? 32 : 64;
$salt = substr($salt, 3);
$rounds = CRYPT_ROUNDS_DEFAULT;
$roundsCustom = false;
if (preg_match('(^rounds=(\d+)\$)i', $salt, $match)) {
$rounds = (int) $match[1];
$salt = substr($salt, strlen($match[0]));
$roundsCustom = true;
}
$saltLen = min(strcspn($salt, '$'), CRYPT_SALT_LEN_MAX);
$salt = substr($salt, 0, $saltLen);
$ctx = hash_init($algo);
hash_update($ctx, $password);
hash_update($ctx, $salt);
$alt = hash($algo, $password . $salt . $password, true);
for ($i = strlen($password); $i > $padLen; $i -= $padLen) {
hash_update($ctx, substr($alt, 0, $padLen));
}
hash_update($ctx, substr($alt, 0, $i));
for ($i = strlen($password); $i > 0; $i >>= 1) {
if (($i & 1) != 0) {
hash_update($ctx, substr($alt, 0, $padLen));
} else {
hash_update($ctx, $password);
}
}
$alt = hash_final($ctx, true);
$temp = hash($algo, str_repeat($password, strlen($password)), true);
$p = substr(str_repeat($temp, ceil(strlen($password) % $padLen)), 0, strlen($password));
$temp = hash($algo, str_repeat($salt, ord($alt[0])+16), true);
$s = substr(str_repeat($temp, ceil(strlen($salt) % $padLen)), 0, strlen($salt));
for ($i = 0; $i < $rounds; $i++) {
$altCtx = hash_init($algo);
if (($i & 1) != 0) {
hash_update($altCtx, $p);
} else {
hash_update($altCtx, $alt);
}
if (($i % 3) != 0) {
hash_update($altCtx, $s);
}
if (($i % 7) != 0) {
hash_update($altCtx, $p);
}
if (($i & 1) != 0) {
hash_update($altCtx, $alt);
} else {
hash_update($altCtx, $p);
}
$alt = hash_final($altCtx, true);
}
$result = $algo === 'sha256' ? '$5$' : '$6$';
if ($roundsCustom) {
$result .= 'rounds=' . $rounds . '$';
}
$result .= $salt . '$';
if ($algo == 'sha256') {
$result .= encode_sha256_crypt($alt);
} else {
$result .= encode_sha512_crypt($alt);
}
return $result;
}
function encode_sha256_crypt($alt) {
$result = b64_from_b24($alt[0], $alt[10], $alt[20], 4);
$result .= b64_from_b24($alt[21], $alt[1], $alt[11], 4);
$result .= b64_from_b24($alt[12], $alt[22], $alt[2], 4);
$result .= b64_from_b24($alt[3], $alt[13], $alt[23], 4);
$result .= b64_from_b24($alt[24], $alt[4], $alt[14], 4);
$result .= b64_from_b24($alt[15], $alt[25], $alt[5], 4);
$result .= b64_from_b24($alt[6], $alt[16], $alt[26], 4);
$result .= b64_from_b24($alt[27], $alt[7], $alt[17], 4);
$result .= b64_from_b24($alt[18], $alt[28], $alt[8], 4);
$result .= b64_from_b24($alt[9], $alt[19], $alt[29], 4);
$result .= b64_from_b24(chr(0), $alt[31], $alt[30], 3);
return $result;
}
function encode_sha512_crypt($alt) {
$result = b64_from_b24($alt[0], $alt[21], $alt[42], 4);
$result .= b64_from_b24($alt[22], $alt[43], $alt[1], 4);
$result .= b64_from_b24($alt[44], $alt[2], $alt[23], 4);
$result .= b64_from_b24($alt[3], $alt[24], $alt[45], 4);
$result .= b64_from_b24($alt[25], $alt[46], $alt[4], 4);
$result .= b64_from_b24($alt[47], $alt[5], $alt[26], 4);
$result .= b64_from_b24($alt[6], $alt[27], $alt[48], 4);
$result .= b64_from_b24($alt[28], $alt[49], $alt[7], 4);
$result .= b64_from_b24($alt[50], $alt[8], $alt[29], 4);
$result .= b64_from_b24($alt[9], $alt[30], $alt[51], 4);
$result .= b64_from_b24($alt[31], $alt[52], $alt[10], 4);
$result .= b64_from_b24($alt[53], $alt[11], $alt[32], 4);
$result .= b64_from_b24($alt[12], $alt[33], $alt[54], 4);
$result .= b64_from_b24($alt[34], $alt[55], $alt[13], 4);
$result .= b64_from_b24($alt[56], $alt[14], $alt[35], 4);
$result .= b64_from_b24($alt[15], $alt[36], $alt[57], 4);
$result .= b64_from_b24($alt[37], $alt[58], $alt[16], 4);
$result .= b64_from_b24($alt[59], $alt[17], $alt[38], 4);
$result .= b64_from_b24($alt[18], $alt[39], $alt[60], 4);
$result .= b64_from_b24($alt[40], $alt[61], $alt[19], 4);
$result .= b64_from_b24($alt[62], $alt[20], $alt[41], 4);
$result .= b64_from_b24(chr(0), chr(0), $alt[63], 2);
return $result;
}
function b64_from_b24($a, $b, $c, $n) {
static $b64t = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$w = (ord($a) << 16) | (ord($b) << 8) | ord($c);
$ret = '';
while ($n-- > 0) {
$ret .= $b64t[$w & 0x3f];
$w >>= 6;
}
return $ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment