用 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 以及在线生成器(如 这个发电机)有很大的不同

有人知道错误是什么吗? 不同的基数?

312207 次浏览

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 是人们仍然需要担心“代码页”的主要原因。)

我也有这个问题与另一种风格的实现,但我忘记了我从哪里得到它,因为它是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 建议的方法修改代码,并将编码从 ASCII改为 UTF8,然后它终于工作了!

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 精彩而详细的回答! :)

在 PHP 版本中,可以在最后一个参数中发送“ true”,但默认值是“ false”。当传递‘ sha256’作为第一个参数时,下面的算法相当于默认 PHP 的 hash 函数:

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;
}
public string EncryptPassword(string password, string saltorusername)
{
using (var sha256 = SHA256.Create())
{
var saltedPassword = string.Format("{0}{1}", salt, password);
byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword);
return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes));
}
}
public static string ComputeSHA256Hash(string text)
{
using (var sha256 = new SHA256Managed())
{
return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
}
}

得到不同结果的原因是因为不使用相同的字符串编码。为计算 SHA256的在线网站放置的链接使用 UTF8编码,而在示例中使用 Unicode 编码。它们是两种不同的编码,所以得到的结果不一样。通过上面的示例,您可以获得链接网站的相同 SHA256散列。在 PHP 中也需要使用相同的编码。

绝对最低限度每个软件开发人员绝对,肯定必须知道 Unicode 和字符集(没有借口!)

Https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

有史以来最短最快的路,只有一条线!

public static string StringSha256Hash(string text) =>
string.IsNullOrEmpty(text) ? string.Empty : BitConverter.ToString(new System.Security.Cryptography.SHA256Managed().ComputeHash(System.Text.Encoding.UTF8.GetBytes(text))).Replace("-", string.Empty);

这在.NET Core 3.1中对我很有用。
但不是在.NET 5预览版7中。

using System;
using System.Security.Cryptography;
using System.Text;


namespace PortalAplicaciones.Shared.Models
{
public class Encriptar
{
public static string EncriptaPassWord(string Password)
{
try
{
SHA256Managed hasher = new SHA256Managed();


byte[] pwdBytes = new UTF8Encoding().GetBytes(Password);
byte[] keyBytes = hasher.ComputeHash(pwdBytes);


hasher.Dispose();
return Convert.ToBase64String(keyBytes);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
}
 

我正在查看和测试这些答案,VisualStudio 向我展示了 SHA256Managed 现在已经过时(给你)

因此,我使用了 SHA256类:

Encoding enc = Encoding.UTF8;
var hashBuilder = new StringBuilder();
using var hash = SHA256.Create();
byte[] result = hash.ComputeHash(enc.GetBytes(yourStringToHash));
foreach (var b in result)
hashBuilder.Append(b.ToString("x2"));
string result = hashBuilder.ToString();

新的.NET 5 + 解决方案:

如果你吸毒的话。NET 5或更高版本,可以使用新的 Convert.ToHexString方法将哈希字节数组转换为十六进制字符串; 消除了使用字符串构建器等的麻烦。

下面的方法还使用 using块,以便释放 SHA256实例。 它还使用 公认的答案推荐的 UTF-8编码将密码(作为字符串传入)转换为字节数组。此外,我们还使用了新的 SHA256类,而不是旧的(现在已经过时了) SHA256Managed类。

public string QuickHash(string secret)
{
using var sha256 = SHA256.Create();
var secretBytes = Encoding.UTF8.GetBytes(secret);
var secretHash = sha256.ComputeHash(secretBytes);
return Convert.ToHexString(secretHash);
}

注意: 您不应该使用此方法散列用户密码。通用散列函数,如 SHA-256不再适合用于密码,即使您添加盐。这对于散列熵很高的字符串很有用,比如随机生成的长会话令牌等等。为了存储密码,您必须查看专门为此目的设计的较慢的哈希函数,如 Bcrypt、 Scrypt 或 PBkdf2(后者在。NET ー请参阅 这个)