<?php
$credential = 'my password';
function BF_crypt_with_legacy_salt($string, $salt)
{
// PHP <=8.1.15 compat: check for $2a$ blowfish salt with dollar
if(strlen($salt) == 29 && substr($salt, 0, 4) == '$2a$' && $salt[6] == '$')
{
$pos = strpos($salt, '$', 7);
if($pos !== false)
{
$pos -= 7;
$itoa = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
// Transform provided salt into something that matches the decoding from PHP 8.1.15
if(($pos & 0x2) == 0)
{
// Offsets 0 and 1: truncate down to even length before the $
$cryptsalt = substr($salt, 0, 7 + ($pos & 0x1e));
}
else
{
// Offsets 2 and 3: truncate to two before the $, and transform the char before the $
$val = strpos($itoa, $salt[7 + ($pos - 1)]);
if($val === false)
{
return '*0';
}
$cryptsalt = substr($salt, 0, 7 + ($pos - 1)).$itoa[$val & (($pos & 0x1) == 0 ? 0x30 : 0x3c)];
}
for($i = 29 - strlen($cryptsalt); $i > 0; --$i)
{
$cryptsalt .= '.';
}
// But we'll actually need a different salt value to prepend to the output
$last = strpos($itoa, $salt[28]);
$textsalt = substr($salt, 0, 28).$itoa[$last === false ? 0 : ($last & 0x30)];
$crypt = crypt($string, $cryptsalt);
// Restore original salt in output
if(substr($crypt, 0, 29) == $cryptsalt)
{
$crypt = $textsalt.substr($crypt, 29);
}
return $crypt;
}
}
// Otherwise just pass through unchanged
return crypt($string, $salt);
}
echo crypt($credential, '$2a$05$SomeDollarSalt9999999$')."\n";
echo BF_crypt_with_legacy_salt($credential, '$2a$05$SomeDollarSalt9999999$')."\n\n";
echo crypt($credential, '$2a$05$SomeDollarSalt999999$9')."\n";
echo BF_crypt_with_legacy_salt($credential, '$2a$05$SomeDollarSalt999999$9')."\n\n";
echo crypt($credential, '$2a$05$SomeDollarSalt99999$99')."\n";
echo BF_crypt_with_legacy_salt($credential, '$2a$05$SomeDollarSalt99999$99')."\n\n";
echo crypt($credential, '$2a$05$SomeDollarSalt9999$999')."\n";
echo BF_crypt_with_legacy_salt($credential, '$2a$05$SomeDollarSalt9999$999')."\n\n";
preferences:
27.73 ms | 406 KiB | 5 Q