长话短说有一个用.NET构建的会员系统,我们正在移植到WordPress并需要复制PBKDF2加密,以便用户不需要重置密码。
使用已知的哈希密码我可以使用以下代码轻松地在.NET中复制此密码:
static void Main(string[] args)
{
var isValid = CheckPassword("#0zEZcD7uNmv", "5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ");
}
public static int PBKDF2IterCount = 10000;
public static int PBKDF2SubkeyLength = 256 / 8; // 256 bits
public static int SaltSize = 128 / 8; // 128 bits
private static bool CheckPassword(string Password, string ExistingHashedPassword)
{
byte[] saltAndPassword = Convert.FromBase64String(ExistingHashedPassword);
byte[] salt = new byte[SaltSize];
Array.Copy(saltAndPassword, 0, salt, 0, SaltSize);
Console.WriteLine("--Salt--");
Console.WriteLine(Convert.ToBase64String(salt));
string hashedPassword = HashPassword(Password, salt);
Console.WriteLine("--HashedPassword--");
Console.WriteLine(hashedPassword);
return hashedPassword == ExistingHashedPassword;
}
private static string HashPassword(string Password, byte[] salt)
{
byte[] hash = new byte[PBKDF2SubkeyLength];
using (var pbkdf2 = new Rfc2898DeriveBytes(Password, salt, PBKDF2IterCount))
{
hash = pbkdf2.GetBytes(PBKDF2SubkeyLength);
}
byte[] hashBytes = new byte[PBKDF2SubkeyLength + SaltSize];
Array.Copy(salt, 0, hashBytes, 0, SaltSize);
Array.Copy(hash, 0, hashBytes, SaltSize, PBKDF2SubkeyLength);
string hashedPassword = Convert.ToBase64String(hashBytes);
return hashedPassword;
}
控制台应用程序将生成以下内容:
--Salt--
5SyOX+Rbclzvvit3MEM2nA==
--HashedPassword--
5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ
--IsValid--
True
然而在PHP方面,我无法获得相同的结果。到目前为止,我的代码如下。
$mySalt = base64_decode('5SyOX+Rbclzvvit3MEM2nA==');
$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 48, true);
$key = substr($dev, 0, 32); //Keylength: 32
$iv = substr($dev, 32, 16); // IV-length: 16
echo 'PHP<br/>';
echo 'PASS: '.base64_encode($dev).'<br/>';
echo 'SALT: '.base64_encode($iv).'<br/><br/>';
echo '.NET<br/>';
echo 'PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ<br/>';
echo 'SALT: 5SyOX+Rbclzvvit3MEM2nA==<br/><br/>';
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
return substr($output, 0, $key_length);
}
结果是:
PHP
PASS: FFo9WjYztlOzuffOddN/Jbg6HBOUku+lxSUKvJuWCRCsYe+1Tgbb8Ob4FtxumMal
SALT: rGHvtU4G2/Dm+BbcbpjGpQ==
.NET
PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ
SALT: 5SyOX+Rbclzvvit3MEM2nA==
任何帮助都将不胜感激。
答案 0 :(得分:4)
使用https://github.com/defuse/password-hashing库完成了它的工作,一些微小的更改与我正在导入的数据库的哈希格式相匹配。
但我的主要问题是这些线路,我试图从哈希中获取密钥。
$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 48, true);
$key = substr($dev, 0, 32); //Keylength: 32
$iv = substr($dev, 32, 16); // IV-length: 16
将其更改为以下内容,以便创建一个32位长的哈希哈希,并将返回的哈希值连接到salt,从而解决问题。
$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 32, true);
echo 'PASS: '.base64_encode($mySalt.$dev).'<br />';
现在下面的输出与.NET匹配:
PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ
答案 1 :(得分:1)
我在寻找将密码从旧版 Asp.Net MVC 应用程序迁移到 Laravel 的方法时遇到了这篇文章。
对于那些只对生成的哈希值进行比较(即用于身份验证)感兴趣的人,请考虑以下事项:
function legacyHashCheck($hash, $password)
{
$raw = base64_decode($hash);
$salt = substr($raw, 1, 16);
$payload = substr($raw, 17, 32);
//new Rfc2898DeriveBytes(password, salt, 1000).GetBytes(32)
$check = hash_pbkdf2('sha1', $password, $salt, 1000, 32, true);
return $payload === $check;
}