繁体   English   中英

使用 Sha256 散列字符串

[英]Hashing a string with Sha256

我尝试使用 SHA256 hash 字符串,我使用以下代码:

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 )相比,此代码给出了明显不同的结果

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

Encoding.Unicode是 Microsoft 对 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 精彩而详细的回答! :)

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/

在 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;
    }
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));
            }
        }

有史以来最短和最快的方式。 只有1行!

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);

我正在寻找和测试这些答案,Visual Studio 向我展示了 SHA256Managed 现在已过时( 此处

所以,我使用了 SHA256 class 代替:

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

全新 .NET 5+ 解决方案:

如果您使用的是 .NET 5 或更高版本,则可以使用新的Convert.ToHexString方法将 hash 字节数组转换为十六进制字符串; 消除使用字符串生成器等的麻烦。

以下还使用using块,以便处置SHA256实例。 它还使用接受的答案建议的 UTF8 编码将密码(作为字符串传入)转换为字节数组。 此外,我们还使用新的SHA256 class,而不是旧的(现已过时的) SHA256Managed class。

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 等通用散列函数不再适合用于密码,即使您添加了盐。 这对于散列您知道具有高熵的字符串很有用,例如长时间随机生成的 session 令牌等等。 为了存储密码,您必须查看专门为此目的设计的较慢的散列函数,例如 Bcrypt、Scrypt 或 PBKDF2(后者在 .NET 中原生可用 - 请参阅

这在 .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);
            }
        }  
    }
}
 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM