在C#中使用SHA1算法进行哈希处理

107

我想使用SHA1Managed算法对给定的byte[]数组进行哈希。
哈希值将从单元测试中获取。
预期哈希值为0d71ee4472658cd5874c5578410a9d8611fc9aef(区分大小写)。

我该如何实现?

public string Hash(byte [] temp)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {

    }
}

2
你期望的哈希值是十六进制的,所以大小写不敏感,例如 hex(e) == hex(E) - jAC
https://dev59.com/gFPTa4cB1Zd3GeqPmclA - TarekSiala
6个回答

216
对于那些想要对哈希进行“标准”文本格式化的人,您可以在 .NET 5 及更高版本中使用以下类似的方法:
static string Hash(string input)
{
    using var sha1 = SHA1.Create();
    return Convert.ToHexString(sha1.ComputeHash(Encoding.UTF8.GetBytes(input)));
}

这将产生一个类似于0C2E99D0949684278C30B9369B82638E1CEAD415的哈希值。
如果你在使用早于.NET 5的版本,其中没有Convert.ToHexString可用,你可以这样做:
static string Hash(string input)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
        var sb = new StringBuilder(hash.Length * 2);

        foreach (byte b in hash)
        {
            // can be "x2" if you want lowercase
            sb.Append(b.ToString("X2"));
        }

        return sb.ToString();
    }
}

或者使用一个精简的 .Net Framework 版本进行代码高尔夫挑战:
static string Hash(string input)
{
    var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
    return string.Concat(hash.Select(b => b.ToString("x2")));
}

1
我感到困扰的是,这个解决方案没有处理SHA1Managed对象,因为它被标记为可处理的。当优化时,这篇文章可能会有帮助:https://dev59.com/Y3VC5IYBdhLWcg3wYQEp#624379 - sky-dev
@sky-dev,我通常会同意 IDisposable,但是快速访问参考源显示在 .Dispose() 中没有发生任何有趣的事情。 - Mitch
32
如果实现了IDisposable接口,那么引用源代码的内容并不重要。但如果以后出于任何原因更改,使得.Dispose()调用变得重要,您之前能正常工作的代码现在将会有问题。依赖于深入了解框架来确定哪些行为是可行的,这是一条通往维护噩梦的道路。我强烈建议遵循文档并正确处理可释放对象,这样会在长期内减少痛苦。 - unenthusiasticuser
1
“X2”是用来做什么的? - ijt
3
@ijt,X2表示每个字节使用两个十六进制数字。 x2 表示小写,X2 表示大写。 - Mitch
显示剩余7条评论

41
public string Hash(byte [] temp)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        var hash = sha1.ComputeHash(temp);
        return Convert.ToBase64String(hash);
    }
}

编辑:

你也可以在将字节数组转换为字符串时指定编码方式,如下所示:

return System.Text.Encoding.UTF8.GetString(hash);
或者
return System.Text.Encoding.Unicode.GetString(hash);

3
如果他们想要一个十六进制字符串,那么Base64可能不是正确的选择。 - Joey
@Joey:针对GrantThomas给出的答案,该成员指出他们需要返回一个字符串。 - John Gathogo
@MerveKaya:也许你应该解释一下你所说的“它没有起作用”是什么意思。传入的字节数组代表什么?你是如何确定对传入的字节数组进行“SHA1Managed”哈希处理后,应该将0d71ee4472658cd5874c5578410a9d8611fc9aef作为输出? - John Gathogo
Byte[]哈希来自单元测试。在问题中,他们写道期望的哈希值是0d71ee4472658cd5874c5578410a9d8611fc9aef。它来自单元测试。 - Merve Kaya
@MerveKaya:请查看我的更新,了解如何在将哈希转换为字符串时使用“编码”。 - John Gathogo
不好意思,很遗憾它又失败了。 - Merve Kaya

19

这就是我选择的方案。对于那些想要进行优化的人,请查看https://dev59.com/Y3VC5IYBdhLWcg3wYQEp#624379

    public static string Hash(string stringToHash)
    {
        using (var sha1 = new SHA1Managed())
        {
            return BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(stringToHash)));
        }
    }

1
我不想使用BitConverter引入的破折号,因此我不得不使用BitConverter.ToString(sha1.ComputeHash(bytes)).Replace("-", "")。之后它就像魔法一样奏效了!谢谢! - Sam

9
最快的方法是这样的:

    public static string GetHash(string input)
    {
        return string.Join("", (new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input))).Select(x => x.ToString("X2")).ToArray());
    }

如果要输出小写字符,请使用x2替换X2


4
SHA1Managed 实现了 IDisposable 接口,因此在使用完毕后最好将其处理掉以释放资源。 - rickythefox
这不是最快的方法,只是被压缩到一行中。 - quetzalcoatl
@quetzalcoatl 嗯,是的 :) - alireza amini

9
您可以使用ComputeHash计算指定字节数组的值。
var hash = sha1.ComputeHash(temp);

如果您想分析字符串表示中的结果,则需要使用{0:X2}格式说明符格式化字节。


4
我来翻译一下:

我也来凑个热闹:

(这段代码是两个扩展方法的一部分,属于静态类)

//hex encoding of the hash, in uppercase.
public static string Sha1Hash (this string str)
{
    byte[] data = UTF8Encoding.UTF8.GetBytes (str);
    data = data.Sha1Hash ();
    return BitConverter.ToString (data).Replace ("-", "");
}
// Do the actual hashing
public static byte[] Sha1Hash (this byte[] data)
{
    using (SHA1Managed sha1 = new SHA1Managed ()) {
    return sha1.ComputeHash (data);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接