2012-09-13 70 views
104

字符串我尝试使用哈希SHA256一个字符串,我使用下面的代码:散列与SHA256

using System; 
using System.Security.Cryptography; 
using System.Text; 
public class Hash 
    { 
    public static string getHashSha256(string text) 
    { 
     byte[] bytes = Encoding.Unicode.GetBytes(text); 
     SHA256Managed hashstring = new SHA256Managed(); 
     byte[] hash = hashstring.ComputeHash(bytes); 
     string hashString = string.Empty; 
     foreach (byte x in hash) 
     { 
      hashString += String.Format("{0:x2}", x); 
     } 
     return hashString; 
    } 
} 

然而,相对于我的朋友的PHP验证码给显著不同的结果,以及在线发电机(如This generator

有谁知道错误是什么?不同的基地?

+11

题外话,但请记住,创建一个StringBuilder并在foreach循环使用AppendFormat代替的String.Format会防止你的代码不必要地创建大量的字符串对象。 –

回答

116

Encoding.Unicode是微软误导性的UTF-16名称(由于历史原因在其他人使用的Windows世界中的双倍宽度编码)。 http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx

如果你检查你的bytes数组,你会看到每个第二个字节是0x00(由于双宽编码)。

您应该使用Encoding.UTF8.GetBytes代替。

但是,根据您是否认为终止的'\0'字节是您哈希的数据的一部分,您将看到不同的结果。散列两个字节"Hi"将给从散列字节"Hi"不同的结果。你必须决定你想要做什么。 (大概你想做你朋友的PHP代码在做的任何一个。)

对于ASCII文本,Encoding.UTF8一定适合。如果你瞄准与您的朋友的代码完美兼容性,甚至在非ASCII输入,你最好多试几个测试用例非ASCII字符,如é,看看你的结果是否仍然匹配。如果没有,你必须弄清楚你的朋友真正使用的是什么编码;它可能是Unicode发明之前流行的8位“代码页”之一。 (同样,我认为Windows是最主要的原因,还有人需要担心“代码页”。)

+0

这是登录系统的一部分,只是切换到UTF8.GetBytes()做了窍门,谢谢:D – Nattfrosten

+0

据我了解,PHP默认使用ASCII。 –

+0

ASCII和UTF-8都适用于所有实际用途,所以,很好。 :)但是我添加了一个段落,指出它们将对高字节字符进行不同的编码,因此可能需要进行一些调整。 – Quuxplusone

64

我也有这个问题,实现另一种风格,但我忘了,我得到了它,因为它是2年前。

static string sha256(string randomString) 
{ 
    var crypt = new SHA256Managed(); 
    string hash = String.Empty; 
    byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(randomString)); 
    foreach (byte theByte in crypto) 
    { 
     hash += theByte.ToString("x2"); 
    } 
    return hash; 
} 

当我输入类似abcdefghi2013由于某种原因,它给我的登录模块不同的结果,并导致错误。 然后我试图修改代码相同的方式,建议的Quuxplusone和ASCIIUTF8那么它终于摸索改变编码!

static string sha256(string randomString) 
{ 
    var crypt = new System.Security.Cryptography.SHA256Managed(); 
    var hash = new System.Text.StringBuilder(); 
    byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString)); 
    foreach (byte theByte in crypto) 
    { 
     hash.Append(theByte.ToString("x2")); 
    } 
    return hash.ToString(); 
} 

再次感谢Quuxplusone的精彩和详细的答案! :)

+0

你的解决方案为我工作。但我有不同的情况。它是用sha512和解决我的问题的代码行是'hash + = bit.ToString(“x2”);'我在这里有一个问题:我正在使用Convert.ToBase64String(byte [] encryptedBytes)从字节到字符串。这给了我不同的结果。那么这两种从字节转换为字符串的方法有什么不同? –

+0

是否可以在这里使用一些自定义(比如我自己的初始化向量)还是附加/预先加入随机字符串选项? – FrenkyB

+0

我并不确定你的意思。这只是一个非常简单的散列函数,您可以随时添加/自定义它。通过追加/预先加入随机字符串,你的意思是腌制?那么这是定制它进一步安全的好方法。 –

-4

可以使用辣椒哈希密码:

private const string _pepper = "P&0myWHq";  

private static string CalculateHashedPassword(string clearpwd) 
{ 
    using (var sha = SHA256.Create()) 
    { 
     var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(clearpwd+_pepper)); 
     return Convert.ToBase64String(computedHash); 
    } 
} 

或者你可以使用的盐(=在数据库中存储与您的哈希密码随机生成的值)

+16

从技术上讲,这是一个胡椒。生成一个盐,并与最终的散列一起存储。辣椒是硬编码或最好存储在安全和/或远程服务器上。 –

+11

@UltromantheTacoman哦,我明白了。我来到这里寻找一个洋葱...将继续寻找然后 – NaN

+4

@NNN这给我的眼睛带来了泪水... – RowanPD

3

在PHP版本可以在最后一个参数中发送'true',但默认值为'false'。过客“SHA256”时,作为第一个参数如下算法相当于默认PHP的散列函数:

public static string GetSha256FromString(string strData) 
    { 
     var message = Encoding.ASCII.GetBytes(strData); 
     SHA256Managed hashString = new SHA256Managed(); 
     string hex = ""; 

     var hashValue = hashString.ComputeHash(message); 
     foreach (byte x in hashValue) 
     { 
      hex += String.Format("{0:x2}", x); 
     } 
     return hex; 
    } 
+3

我不会使用'ASCII'并做'byte [] arrBytes = System.Text.Encoding .UTF8.GetBytes(strData)'而不是。 – c00000fd