1. 程式人生 > 程式設計 >.NET6中雜湊演算法的簡化用法的實現

.NET6中雜湊演算法的簡化用法的實現

目錄
  • Intro
  • New API
  • Sample Before
  • New API Sample
  • More
  • References

Intro

微軟在 .NET 6 中引入一些更簡單的 API 來使用 HMAC 雜湊演算法(MD5/SHA1/SHA256/SHA384/SHA512)

微軟的叫法叫做 HMAC One-Shoot method,HMAC 演算法在普通的雜湊演算法基礎上增加了一個 key,通過 key 提升了安全性,能夠有效避免密碼洩露被彩虹表反推出真實密碼, JWT(on Web Token) 除了可以使用 RSA 方式外也支援使用 HMAC 。

New API

新增的 API 定義如下:

namespace System.Security.Cryptography { 
    public partial class HMACMD5 { 
        public static byte[] HashData(byte[] key,byte[] source); 
        public static byte[] HashData(ReadOnlySpan<byte> key,ReadOnlySpan<byte> source); 
        public static int HashData(ReadOnlySpan<byte> key,ReadOnlySpan<byte> source,Span<byte> destination); 
        public static bool TryHashData(ReadOnlySpan<byte> key,Span<byte> destination,out int bytesWritten); 
    } 
 
    public partial class HMACSHA1 { 
        public static byte[] HashData(byte[] key,out int bytesWritten); 
    } 
 
    public partial class HMACSHA256 { 
        public static byte[] HashData(byte[] key,out int bytesWritten); 
    } 
 
    public partial class HMACSHA384 { 
        public static byte[] HashData(byte[] key,out int bytesWritten); 
    } 
 
    public partial class HMACSHA512 { 
        public static byte[] HashData(byte[] key,out int bytesWritten); 
    } 
} 

Sample Before

在之前的版本中想要實現計算 HMAC 演算法會比較複雜,之前實現了一個 HashHelper 來封裝了常用的 Hash 演算法和 HMAC 演算法,HashHelper 部分程式碼如下,完整程式碼可以從 獲取:https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/HashHelper.cs

/// <summary> 
/// 獲取雜湊之後的字串 
/// </summary> 
/// <param name="type">雜湊型別</param> 
/// <param name="source">源</param> 
/// <param name="key">key</param> 
/// <param name="isLower">是否是小寫</param> 
/// <returns>雜湊演算法處理之後的字串</returns> 
public static string GetHashedString(HashType type,byte[] source,byte[]? key,bool isLower = false) 
{ 
    Guard.NotNull(source,nameof(source)); 
    if (source.Length == 0) 
    { 
        return string.Empty; 
    } 
    var hashedBytes = GetHashedBytes(type,source,key); 
    var sbText = new StringBuilder(); 
    if (isLower) 
    { 
        foreach (var b in hashedBytes) 
        { 
            sbText.Append(b.ToString("x2")); 
        } 
    } 
    else 
    { 
        foreach (var b in hashedBytes) 
        { 
            sbText.Append(b.ToString("X2")); 
        } 
    } 
    return sbText.ToString(); 
} 
 
/// <sEZVmKngVMx
ummary> /// 計算字串Hash值 /// </summary> /// <param name="type">hash型別</param> /// <param name="str">要hash的字串</param> /// <returns>hash過的位元組陣列</returns> public static byte[] GetHashedBytes(HashType type,string str) => GetHashedBytes(type,str,Encoding.UTF8); /// <summary> /// 計算字串Hash值 /// </summary> /// <param name="type">hash型別</param> /// <param name="str">要hash的字串</param> /// <param name="encoding">編碼型別</param> /// <returns>hash過的位元組陣列</returns> public static byte[] GetHashedBytes(HashType type,string str,Encoding encoding) { Guard.NotNull(str,nameof(str)); if (str == string.Empty) { return Array.Empty<byte>(); } var bytes = encoding.GetBytes(str); return GetHashedBytes(type,bytes); } /// <summary> /// 獲取Hash後的位元組數EZVmKngVMx
組 /// </summary> /// <param name="type">雜湊型別</param> /// <param name="bytes">原位元組陣列</param> /// <returns></returns> public static byte[] GetHashedBytes(HashType type,byte[] bytes) => GetHashedBytes(type,bytes,null); /// <summary> /// 獲取Hash後的位元組陣列 /// </summary> /// <param name="type">雜湊型別</param> /// <param name="key">key</param> /// <param name="bytes">原位元組陣列</param> /// <returns></returns> public static byte[] GetHashedBytes(HashType type,byte[] bytes,byte[]? key) { Guard.NotNull(bytes,nameof(bytes)); if (bytes.Length == 0) { return bytes; } HashAlgorithm algorithm = null!; try { if (key == null) { algorithm = http://www.cppcns.comtype switch { HashType.SHA1 => new SHA1Managed(),HashType.SHA256 => new SHA256Managed(),HashType.SHA384 => new SHA384Managed(),HashType.SHA512 => new SHA512Managed(),_ => MD5.Create() }; } else { algorithm = type switch { HashType.SHA1 => new HMACSHA1(key),HashType.SHA256 => new HMACSHA256(key),HashType.SHA384 => new HMACSHA384(key),HashType.SHA512 => new HMACSHA512(key),_ => new HMACMD5(key) }; } return algorithm.ComputeHash(bytes); } finally { algorithm.Dispose(); } }

使用示例如下:

HashHelper.GetHashedBytes(HashType.MD5,"test"); 
HashHelper.GetHashedBytes(HashType.MD5,"test".GetBytes()); 
HashHelper.GetHashedBytes(HashType.MD5,"test","testKey"); 
HashHelper.GetHashedBytes(HashType.MD5,"test".GetBytes(),"testKey".GetBytes()); 
 
HashHelper.GetHashedString(HashType.MD5,"test"); 
HashHelper.GetHashedString(HashType.SHA1,"test".GetBytes()); 
HashHelper.GetHashedString(HashType.SHA256,"testKey"); 
HashHelper.GetHashedString(HashType.MD5,"testKey".GetBytes()); 

New API Sample

有了新的 API 以後可以怎麼簡化呢,來看下面的示例:

var bytes = "test".GetBytes(); 
var keyBytes = "test-key".GetBytes(); 
 
// HMACMD5 
var hmd5V1 = HMACMD5.HashData(keyBytes,bytes); 
var hmd5V2 = HashHelper.GetHashedBytes(HashType.MD5,keyBytes); 
Console.WriteLine(hmd5V2.SequenceEqual(hmd5V1)); 
 
// HMACSHA1 
var hsha1V1 = HMACSHA1.HashData(keyBytes,bytes); 
var hsha1V2 = HashHelper.GetHashedBytes(HashType.SHA1,keyBytes); 
Console.WriteLine(hsha1V2.SequenceEqual(hsha1V1)); 
 
// HMACSHA256 
var hsha256V1 = HMACSHA256.HashData(keyBytes,bytes); 
var hsha256V2 = HashHelper.GetHashedBytes(HashType.SHA256,keyBytes); 
Console.WriteLine(hsha256V2.SequenceEqual(hsha256V1)); 
 
// HMACSHA384 
var hsha384V1 = HMACSHA384.HashData(keyBytes,bytes); 
var hsha384V2 = HashHelper.GetHashedBytes(HashType.SHA384,keyBytes); 
Console.WriteLine(hsha384V2.SequenceEqual(hsha384V1)); 
 
// HMACSHA512 
var hsha512V1 = HMACSHA512.HashData(keyBytes,bytes); 
var hsha512V2 = HashHelper.GetHashedBytes(HashType.SHA512,keyBytes); 
Console.WriteLine(hsha512V2.SequenceEqual(hsha512V1)); 

直接使用對應的 HMAC 雜湊演算法的 HashData 方法即可,傳入對應的 key 和 原始內容就可以了,上面是和我們 HashHelper 封裝的方法進行對比,看結果是否一致,都是一致的,輸出結果如下:

.NET6中雜湊演算法的簡化用法的實現

More

對於普通的雜湊演算法,微軟其實在 .NET 5 就已經支援了上面的用法,可以嘗試一下下面的程式碼:

var bytes = "test".GetBytes(); 
 
// MD5 
var md5V1 = MD5.HashData(bytes); 
var md5V2 = HashHelper.GetHashedBytes(HashType.MD5,bytes); 
Console.WriteLine(md5V2.SequenceEqual(md5V1)); 
 
// SHA1 
var sha1V1 = SHA1.HashData(bytes); 
var sha1V2 = HashHelper.GetHashedBytes(HashType.SHA1,bytes); 
Console.WriteLine(sha1V2.SequenceEqual(sha1V1)); 
 
// SHA256 
var sha256V1 = SHA256.HashData(bytes); 
var sha256V2 = HashHelper.GetHashedBytes(HashType.SHA256,bytes); 
Console.WriteLine(sha256V2.SequenceEqual(sha256V1)); 
 
// SHA384 
var sha384V1 = SHA384.HashData(bytes); 
var sha384V2 = HashHelper.GetHashedBytes(HashType.SHA384,bytes); 
Console.WriteLine(sha384V2.SequenceEqual(sha384V1)); 
 
// SHA512 
var sha512V1 = SHA512.HashData(bytes); 
var sha512V2 = HashHelper.GetHashedBytes(HashType.SHA512,bytes); 
Console.WriteLine(sha512V2.SequenceEqual(sha512V1)); 

很多時候我們可能都會要使用 MD5 或者 SHA1 之後的字串,不知道為什麼微軟沒有直接獲取一個字串的方法,如果有這樣一個方法,就會更方便了,相比之後,感覺還是自己封裝的 HashHelper 使用起來更舒服一些,哈哈,這樣的靜態方法不夠抽象如果要動態替換雜湊演算法程式碼可能就有點...

References

https://github.com/dotnet/runtime/pull/53487
https://github.com/dotnet/runtime/issues/40012
https://github.com/dotnet/core/issues/6569#issuecomment-913876347
https://baike.baidu.com/item/hmac/7307543?fr=aladdin
https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/HashSample/Program.cs
https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/HashHelper.cs

到此這篇關於.NET 6中雜湊演算法的簡化用法的實現的文章就介紹到這了,更多相關.NET 6 雜湊演算法內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!