加入收藏 | 设为首页 | 会员中心 | 我要投稿 拼字网 - 核心网 (https://www.hexinwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

.NET 6 中哈希算法 的简化用途

发布时间:2022-11-25 12:38:34 所属栏目:语言 来源:
导读:  微软在 .NET 6 中引入一些更简单的 API 来使用 HMAC 哈希算法(MD5/SHA1/SHA256/SHA384/SHA512)
  
  微软的叫法叫做 HMAC One-Shoot method, HMAC 算法在普通的哈希算法基础上增加了一个 key,通过 key 提
  微软在 .NET 6 中引入一些更简单的 API 来使用 HMAC 哈希算法(MD5/SHA1/SHA256/SHA384/SHA512)
  
  微软的叫法叫做 HMAC One-Shoot method, HMAC 算法在普通的哈希算法基础上增加了一个 key,通过 key 提升了安全性,能够有效避免密码泄露被彩虹表反推出真实密码, JWT(Json 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, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
      }
  
      public partial class HMACSHA1 {
          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, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
      }
  
      public partial class HMACSHA256 {
          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, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
      }
  
      public partial class HMACSHA384 {
          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, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
      }
  
      public partial class HMACSHA512 {
          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, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
      }
  }
  Sample Before
  在之前的版本中想要实现计算 HMAC 算法会比较复杂,之前实现了一个 HashHelper 来封装了常用的 Hash 算法和 HMAC 算法,HashHelper 部分代码如下,完整代码可以从 Github 获取: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();
  }
  
  /// <summary>
  /// 计算字符串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后的字节数组
  /// </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 = type 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, "test", "testKey");
  HashHelper.GetHashedString(HashType.MD5, "test".GetBytes(), "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, bytes, keyBytes);
  Console.WriteLine(hmd5V2.SequenceEqual(hmd5V1));
  
  // HMACSHA1
  var hsha1V1 = HMACSHA1.HashData(keyBytes, bytes);
  var hsha1V2 = HashHelper.GetHashedBytes(HashType.SHA1, bytes, keyBytes);
  Console.WriteLine(hsha1V2.SequenceEqual(hsha1V1));
  
  // HMACSHA256
  var hsha256V1 = HMACSHA256.HashData(keyBytes, bytes);
  var hsha256V2 = HashHelper.GetHashedBytes(HashType.SHA256, bytes, keyBytes);
  Console.WriteLine(hsha256V2.SequenceEqual(hsha256V1));
  
  // HMACSHA384
  var hsha384V1 = HMACSHA384.HashData(keyBytes ,bytes);
  var hsha384V2 = HashHelper.GetHashedBytes(HashType.SHA384, bytes, keyBytes);
  Console.WriteLine(hsha384V2.SequenceEqual(hsha384V1));
  
  // HMACSHA512
  var hsha512V1 = HMACSHA512.HashData(keyBytes ,bytes);
  var hsha512V2 = HashHelper.GetHashedBytes(HashType.SHA512, bytes, keyBytes);
  Console.WriteLine(hsha512V2.SequenceEqual(hsha512V1));
 

(编辑:拼字网 - 核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!