我们的客户端拥有数千个旧密码哈希,他们希望我们能够验证/匹配,以便将这些登录信息转移到更现代的安全考虑范围。
哈希是类似SHA1(十六进制和40个字符),并且是在ASP.NET中生成的。我们有一些测试用例具有明文密码,base64编码的salt和base64编码的哈希 - 我们需要能够根据给定的密码和盐重现哈希值。
我一直在使用https://forums.asp.net/p/1336657/2899172.aspx作为编写PHP脚本来重现哈希的参考。这是我尝试直接重写的片段:
public string EncodePassword(string pass, string saltBase64)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] src = Convert.FromBase64String(saltBase64);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
看起来很简单 - 获取密码的字节数组,base64-decode salt,连接它们,然后通过SHA1运行它们。我觉得我有90%的方式,但无论我尝试什么变种,我都无法成功匹配提供的哈希值!
我怀疑我尝试复制Encoding.Unicode.GetBytes
是问题 - unpack
可能并不等同。但经过一个小时左右的搜索,我无法找到任何接近的方法。不是ASP开发人员,我确信我有一些细微差别 - 有人能指出哪里出错了吗?
这是我的测试输出代码:
$test = [
'plaintext' => 'overthis2:)',
'salt' => '7LeJR68EGhBgaE7EYgL/gg==',
'hash' => 'g54KVV4Wj5smOyXHOReyWnTnGDc='
];
$algos = [ 'sha1', 'ripemd160', 'tiger160,3', 'tiger160,4', 'haval160,3', 'haval160,4', 'haval160,5' ];
$raw = implode( '', unpack( "H*", $test['plaintext'] ) ) . base64_decode( $test['salt'] );
echo 'Plaintext: ' . $test['plaintext'] . "\n";
echo 'Salt: ' . $test['salt'] . "\n";
echo 'Raw: ' . $raw . "\n\n";
echo 'Saved hash: ' . $test['hash'] . "\n";
echo 'Decoded: ' . bin2hex( base64_decode( $test['hash'] ) ) . "\n\n";
foreach ( $algos as $algo ) {
echo str_pad( $algo . ':' , 15, ' ' ) . hash( $algo, $raw ) . "\n";
}
这里得到的结果 - 没有任何哈希符合提供的内容:
Plaintext: overthis2:)
Salt: 7LeJR68EGhBgaE7EYgL/gg==
Raw: 6f76657274686973323a29췉G�`hN�b��
Saved hash: g54KVV4Wj5smOyXHOReyWnTnGDc=
Decoded: 839e0a555e168f9b263b25c73917b25a74e71837
sha1: d0b448e50d81e6a42601ebcc8e7aa07423d12210
ripemd160: 4359afa37173388db43c47db5188cf5cc47f30d9
tiger160,3: c2e22500127cef7141077049e9bda7747e0b298d
tiger160,4: e03fc57f1d9259cd650aab3682cf54609a30d62b
haval160,3: 437838726fc63fb15969e1c5f0b34dc7f404cabc
haval160,4: ec5cb7e38fe28534b65d25fabf756113c9e563d6
haval160,5: 48551660bbc519bb7db8d595556f4f167eeec749
答案 0 :(得分:2)
.NET代码将密码处理为UTF16LE字符串(Encoding.Unicode
),因此每个字符都是16位宽。这意味着在这种情况下,该部分中的每个其他字节都为零。
你也有错误的方法和密码,没有必要解压缩任何东西,.NET代码不使用十六进制值,而是使用原始字节。
进行此更改,您将获得相同的哈希值:
$raw = base64_decode( $test['salt'] ).implode("\0", str_split($test['plaintext']))."\0";
这只需要盐,对其进行解码,然后通过在每个字符后面添加一个零字节将密码转换为UTF16。