如何在C#中对字符串进行SHA512哈希?

65

我正试图编写一个函数,以这种方式对字符串进行sha512哈希处理:

public string SHA512(string input)
{
     string hash;

     ~magic~

     return hash;
}

魔法应该是什么?

13个回答

94

你的代码是正确的,但是你应该释放SHA512Managed实例:

using (SHA512 shaM = new SHA512Managed())
{
   hash = shaM.ComputeHash(data);
}

512位等于64字节。

要将字符串转换为字节数组,您需要指定编码方式。如果您想创建一个哈希码,UTF8是可以的:

var data = Encoding.UTF8.GetBytes("text");    
using (...

17
没使用dispose方法的示例数量惊人。称赞你展示了使用“using”语句的惯用方式。 - Jesse C. Slicer
4
使用var data = Encoding.UTF8.GetBytes(foo)代替var data = Encoding.UTF8.GetByteCount(foo)。注意保持原意,使语言更通俗易懂。 - luiscubal
1
为什么需要“using”语句?默认的 C# 垃圾回收不会清除 shaM 变量吗?为什么需要像这样显式地进行垃圾回收? - Brian Birtle
7
不要混淆垃圾回收和释放/处理未使用的非托管对象。使用 "using" 可以确保在 using 块结束时调用 Dispose。这将释放非托管资源 - 否则它们将在 GC 清理对象时(并在内部调用终结器)被释放。类 SHA512Managed 是可释放的,所以我更喜欢使用 using。有关 Dispose 模式的更多信息,请查看 https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx - Carsten Schütte
在.NET 6中,它会抛出警告Warning SYSLIB0021 'SHA512Managed'已过时:派生的加密类型已过时。请改用基类型上的Create方法。' 如何在.NET 6中使用它? 在https://dev59.com/4lEG5IYBdhLWcg3wOXKV中有单独的问题。 - Andrus

43

这是我其中一个项目的内容:

public static string SHA512(string input)
{
    var bytes = System.Text.Encoding.UTF8.GetBytes(input);
    using (var hash = System.Security.Cryptography.SHA512.Create())
    {
        var hashedInputBytes = hash.ComputeHash(bytes);

        // Convert to text
        // StringBuilder Capacity is 128, because 512 bits / 8 bits in byte * 2 symbols for byte 
        var hashedInputStringBuilder = new System.Text.StringBuilder(128);
        foreach (var b in hashedInputBytes)
            hashedInputStringBuilder.Append(b.ToString("X2"));
        return hashedInputStringBuilder.ToString();
    }
}

请注意:
  1. SHA512对象已经被销毁('using'部分),所以我们没有任何资源泄漏。
  2. 为了有效地构建十六进制字符串,使用了StringBuilder。

10
StringBuilder 代码可以被以下一行代码替换: 'var hash = BitConverter.ToString(hashedInputBytes).Replace("-", "");' https://msdn.microsoft.com/zh-cn/library/system.bitconverter.tostring(v=vs.110).aspx - Michael Freidgeim

8

是的,你绝对正确。我只是用了一个在线生成器来进行比较,这使得十六进制。谢谢 :) - James
该链接并不是将字符串转换为字节数组,而是将十六进制字符串转换为字节。要将字符串转换为字节数组,请使用类似于 Encoding.UTF8.GetByteCount("text") 的方法。 - Carsten Schütte
@CarstenSchütte 嗯,UTF-8 是用于文本编码的,与此问题无关。无论如何,GetByteCount 不会将字符串转换为字节数组。它只会获取字节数组的 长度 - luiscubal
@CarstenSchütte 哦,等等。我想我知道你的意思了。你是在谈论获取初始的“data”变量,对吧?在这种情况下,是的,UTF-8 是可以的。不过,GetByteCount 仍然不是合适的函数。 - luiscubal
@luiscubal:对不起,GetByteCount 是我的错误(和复制/粘贴错误)。当然,你需要使用 GetBytes() 来获取数据。 - Carsten Schütte

4
你可��尝试使用以下这些代码行:
public static string GenSHA512(string s, bool l = false)
{
    string r = "";

    try
    {
        byte[] d = Encoding.UTF8.GetBytes(s);

        using (SHA512 a = new SHA512Managed())
        {
            byte[] h = a.ComputeHash(d);
            r = BitConverter.ToString(h).Replace("-", "");
        }

        r = (l ? r.ToLowerInvariant() : r);
    }
    catch
    {

    }

    return r;
}
  1. 它被置于末尾
  2. 它是安全的
  3. 支持小写字母

2

您可以使用BouncyCastle替换WinCrypt-API中的System.Security.Cryptography。

public static byte[] SHA512(string text)
{
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);

    Org.BouncyCastle.Crypto.Digests.Sha512Digest digester = new Org.BouncyCastle.Crypto.Digests.Sha512Digest();
    byte[] retValue = new byte[digester.GetDigestSize()];
    digester.BlockUpdate(bytes, 0, bytes.Length);
    digester.DoFinal(retValue, 0);
    return retValue;
}

如果您需要HMAC版本(用于向哈希添加身份验证),请使用以下步骤:
public static byte[] HmacSha512(string text, string key)
{
    byte[] bytes = Encoding.UTF8.GetBytes(text);

    var hmac = new Org.BouncyCastle.Crypto.Macs.HMac(new Org.BouncyCastle.Crypto.Digests.Sha512Digest());
    hmac.Init(new Org.BouncyCastle.Crypto.Parameters.KeyParameter(System.Text.Encoding.UTF8.GetBytes(key)));

    byte[] result = new byte[hmac.GetMacSize()];
    hmac.BlockUpdate(bytes, 0, bytes.Length);
    hmac.DoFinal(result, 0);

    return result;
}

1
BouncyCastle是什么? - Mikael Dúi Bolinder
2
@MikaelDúiBolinder:Bouncy Castle Crypto APIs由澳大利亚慈善组织Bouncy Castle军团管理,该组织负责照顾和维护Bouncy Castle APIs。https://www.bouncycastle.org/ - Stefan Steiger

2

简单明了:

using (SHA512 sha512 = new SHA512Managed())
{
    password = Encoding.UTF8.GetString(sha512.ComputeHash(Encoding.UTF8.GetBytes(password)));
}

1

我不确定你为什么期望128。

一个字节有8位。64个字节。8 * 64 = 512位哈希值。


1
MSDN文档中得知:
SHA512Managed算法的哈希大小为512位。

1

我将其制作成了一个扩展方法,放在我的ExtensionUtility.cs类中。

public static string SHA512(this string plainText)
    {
      
        using (SHA512 shaM = new SHA512Managed())
        {
            var buffer = Encoding.UTF8.GetBytes(plainText);
            var hashedInputBytes = shaM.ComputeHash(buffer);

           return BitConverter.ToString(hashedInputBytes).Replace("-", "");

        }
    }

1

您可以使用System.Security.Cryptography.SHA512类

SHA512的MSDN文档

这里有一个例子,直接来自MSDN

byte[] data = new byte[DATA_SIZE];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(data);

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