PHP等价于C#SHA1 Unicode哈希
我有一个正在运行的带有用户身份验证的C#应用程序。我使用Encoding.Unicode使用SHA1Managed类加密密码。现在,我们正在开发一个新的PHP web应用程序,PHP sha1方法似乎使用ASCII,因此加密的密码略有不同 我无法更改我的C#代码,因为它在许多不同的服务器上运行,并且所有用户密码都已加密。这不能改变,因为这意味着询问所有用户他们的密码(这是不可行的) 我已经阅读了以下解决方案,但我无法用它们解决我的问题:PHP等价于C#SHA1 Unicode哈希,c#,php,unicode,hash,sha1,C#,Php,Unicode,Hash,Sha1,我有一个正在运行的带有用户身份验证的C#应用程序。我使用Encoding.Unicode使用SHA1Managed类加密密码。现在,我们正在开发一个新的PHP web应用程序,PHP sha1方法似乎使用ASCII,因此加密的密码略有不同 我无法更改我的C#代码,因为它在许多不同的服务器上运行,并且所有用户密码都已加密。这不能改变,因为这意味着询问所有用户他们的密码(这是不可行的) 我已经阅读了以下解决方案,但我无法用它们解决我的问题: 在这篇文章中,他们建议使用密码。然而,正如我之前所说,这是
byte[]msgBytes=Encoding.Unicode.GetBytes(数据);
sha1管理的sha1=新的sha1管理的();
byte[]hashBytes=sha1.ComputeHash(msgBytes);
StringBuilder hashRet=新的StringBuilder(“”);
foreach(hashBytes中的字节b)
AppendFormat(“{0:X}”,b);
返回hashRet.ToString();
这是迄今为止实现的PHP代码:
$str=mb\u convert\u编码($password.$SALT,'UTF-16LE');
$result=strtoupper(sha1($str));
C语言中示例字符串“1981”的结果#
D4CEDCADB729F37C30EBF41BC8F2929AF526AD3
在PHP中,我得到:
D4CEDCADB729F37C30EBF41BC8F29209AF526AD3
可以看出,每个字符之间的唯一区别是0(零)个字符。这在所有字符串中都会发生,但0显示在不同的位置
编辑
如上所述,结果不能像我的字符串中有盐一样完全复制。然而,即使没有盐,结果也应该不同
解决方案
一位用户提出了解决我问题的建议。不幸的是,他在我发布答案之前就删除了答案。问题是在C#中,当我在StringBuilder中将字节解析为字符串时。格式为{0:X},字节中的任何前导0都将被忽略。例如,01将被解析为1,0D将被解析为D
所以,我必须迭代在PHP中获得的结果对,并删除其中的前导零
PHP中的最终代码如下所示:
$str=mb\u convert\u编码($password.$SALT,'UTF-16LE');
$result=strtoupper(sha1($str));
$array=str_split($result,2);
foreach($array as&$valor){
$valor=ltrim($valor,'0');
}
unset($valor);
$result=内爆($array);
你不会喜欢我的答案,但在这里。首先,问题不在于PHP,PHP很简单,而且工作正常。你的C代码中有一个严重的错误。它需要尽快修复 这不能改变,因为这意味着询问所有用户他们的密码(这是不可行的) 不幸的是,这是必须发生的事情。但你可以在不引起群众恐慌的情况下做到这一点。我假设您的数据库有某种方式知道管理员是否重置了密码;如果没有,那么您需要添加这样的列(最好是timestamp类型)。下次用户登录时,他们必须提供密码,因为您已经重置了所有密码,所以请使用该密码并正确地重新刷新它,并将新的哈希存储在数据库中。明智的做法是为新散列使用一个新列,或者至少有一种方法来识别正确的散列。该列至少应该是VARCHAR(60),但最好是使用VARCHAR(255),它应该容纳所有流行的哈希 当然,SHA1不是一种适合密码的散列方法,即使使用盐。因为您需要重新设置所有密码,所以最好切换到bcrypt或类似的安全哈希函数 因为您的原始应用程序引入了这个bug,所以您需要一些变通方法。在新应用程序中支持错误行为似乎不是一个好主意,因此我建议不要在PHP中寻找解决方法。当然,您可以尝试以与问题中建议的相同方式损坏密码,但这只会将相同的错误拖到新应用程序中,而根本不会修复它 在开始做任何事情之前,您应该分析数据库中有多少密码被损坏。正确的SHA1哈希长度应为40个字符。如果你能找到少于40个的密码,你就会知道需要修改哪些密码和多少密码 修复密码会很困难,但绝对值得 关于字符编码的说明:
PHP大部分时间使用UTF-8编码。这是web上最常用的编码,我建议您对字符串使用这种编码。当谈到散列时,字符串的编码是什么并不重要,因为散列是按字节计算的。这就是为什么要使用
Encoding.Unicode.GetBytes(data)
将C#字符串转换为UTF-16中的字节 SHA1的可能副本不是加密方法,而是哈希函数。SHA1不适用于密码。你应该使用安全的散列方法,比如bcrypt。我既不能在@Herohtar中复制你的结果,也不能在@Herohtar中复制你的结果,因为我没有使用base64encoding@Dharman你是对的,我刚刚用你的观察和解决问题的最终答案编辑了这篇文章。非常感谢你的观察。我会深入研究,并作出所有必要的更正。