Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP等价于C#SHA1 Unicode哈希_C#_Php_Unicode_Hash_Sha1 - Fatal编程技术网

PHP等价于C#SHA1 Unicode哈希

PHP等价于C#SHA1 Unicode哈希,c#,php,unicode,hash,sha1,C#,Php,Unicode,Hash,Sha1,我有一个正在运行的带有用户身份验证的C#应用程序。我使用Encoding.Unicode使用SHA1Managed类加密密码。现在,我们正在开发一个新的PHP web应用程序,PHP sha1方法似乎使用ASCII,因此加密的密码略有不同 我无法更改我的C#代码,因为它在许多不同的服务器上运行,并且所有用户密码都已加密。这不能改变,因为这意味着询问所有用户他们的密码(这是不可行的) 我已经阅读了以下解决方案,但我无法用它们解决我的问题: 在这篇文章中,他们建议使用密码。然而,正如我之前所说,这是

我有一个正在运行的带有用户身份验证的C#应用程序。我使用Encoding.Unicode使用SHA1Managed类加密密码。现在,我们正在开发一个新的PHP web应用程序,PHP sha1方法似乎使用ASCII,因此加密的密码略有不同

我无法更改我的C#代码,因为它在许多不同的服务器上运行,并且所有用户密码都已加密。这不能改变,因为这意味着询问所有用户他们的密码(这是不可行的)

我已经阅读了以下解决方案,但我无法用它们解决我的问题:

  • 在这篇文章中,他们建议使用密码。然而,正如我之前所说,这是无法改变的
  • 这一个使用base64编码,这与我的C#编码不兼容(我想)
  • 这一个也使用了asciencoding
  • 这是我的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你是对的,我刚刚用你的观察和解决问题的最终答案编辑了这篇文章。非常感谢你的观察。我会深入研究,并作出所有必要的更正。