请选择 进入手机版 | 继续访问电脑版

[ASP.NET] .NET6中哈希算法的简化用法的实现

  [复制链接]
查看331 | 回复80 | 2021-9-15 08:14:54 | 显示全部楼层 |阅读模式
目次

Intro

微软在 .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 定义如下:

  1. namespace System.Security.Cryptography {
  2. public partial class HMACMD5 {
  3. public static byte[] HashData(byte[] key, byte[] source);
  4. public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
  5. public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
  6. public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
  7. }
  8. public partial class HMACSHA1 {
  9. public static byte[] HashData(byte[] key, byte[] source);
  10. public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
  11. public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
  12. public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
  13. }
  14. public partial class HMACSHA256 {
  15. public static byte[] HashData(byte[] key, byte[] source);
  16. public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
  17. public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
  18. public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
  19. }
  20. public partial class HMACSHA384 {
  21. public static byte[] HashData(byte[] key, byte[] source);
  22. public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
  23. public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
  24. public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
  25. }
  26. public partial class HMACSHA512 {
  27. public static byte[] HashData(byte[] key, byte[] source);
  28. public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
  29. public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
  30. public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);
  31. }
  32. }
复制代码

Sample Before

在之前的版本中想要实现计算 HMAC 算法会比较复杂,之前实现了一个 HashHelper 来封装了常用的 Hash 算法和 HMAC 算法,HashHelper 部分代码如下,完备 代码可以从 Github 获取:https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/HashHelper.cs

  1. /// <summary>
  2. /// 获取哈希之后的字符串
  3. /// </summary>
  4. /// <param name="type">哈希类型</param>
  5. /// <param name="source">源</param>
  6. /// <param name="key">key</param>
  7. /// <param name="isLower">是否是小写</param>
  8. /// <returns>哈希算法处理之后的字符串</returns>
  9. public static string GetHashedString(HashType type, byte[] source, byte[]? key, bool isLower = false)
  10. {
  11. Guard.NotNull(source, nameof(source));
  12. if (source.Length == 0)
  13. {
  14. return string.Empty;
  15. }
  16. var hashedBytes = GetHashedBytes(type, source, key);
  17. var sbText = new StringBuilder();
  18. if (isLower)
  19. {
  20. foreach (var b in hashedBytes)
  21. {
  22. sbText.Append(b.ToString("x2"));
  23. }
  24. }
  25. else
  26. {
  27. foreach (var b in hashedBytes)
  28. {
  29. sbText.Append(b.ToString("X2"));
  30. }
  31. }
  32. return sbText.ToString();
  33. }
  34. /// <summary>
  35. /// 计算字符串Hash值
  36. /// </summary>
  37. /// <param name="type">hash类型</param>
  38. /// <param name="str">要hash的字符串</param>
  39. /// <returns>hash过的字节数组</returns>
  40. public static byte[] GetHashedBytes(HashType type, string str) => GetHashedBytes(type, str, Encoding.UTF8);
  41. /// <summary>
  42. /// 计算字符串Hash值
  43. /// </summary>
  44. /// <param name="type">hash类型</param>
  45. /// <param name="str">要hash的字符串</param>
  46. /// <param name="encoding">编码类型</param>
  47. /// <returns>hash过的字节数组</returns>
  48. public static byte[] GetHashedBytes(HashType type, string str, Encoding encoding)
  49. {
  50. Guard.NotNull(str, nameof(str));
  51. if (str == string.Empty)
  52. {
  53. return Array.Empty<byte>();
  54. }
  55. var bytes = encoding.GetBytes(str);
  56. return GetHashedBytes(type, bytes);
  57. }
  58. /// <summary>
  59. /// 获取Hash后的字节数组
  60. /// </summary>
  61. /// <param name="type">哈希类型</param>
  62. /// <param name="bytes">原字节数组</param>
  63. /// <returns></returns>
  64. public static byte[] GetHashedBytes(HashType type, byte[] bytes) => GetHashedBytes(type, bytes, null);
  65. /// <summary>
  66. /// 获取Hash后的字节数组
  67. /// </summary>
  68. /// <param name="type">哈希类型</param>
  69. /// <param name="key">key</param>
  70. /// <param name="bytes">原字节数组</param>
  71. /// <returns></returns>
  72. public static byte[] GetHashedBytes(HashType type, byte[] bytes, byte[]? key)
  73. {
  74. Guard.NotNull(bytes, nameof(bytes));
  75. if (bytes.Length == 0)
  76. {
  77. return bytes;
  78. }
  79. HashAlgorithm algorithm = null!;
  80. try
  81. {
  82. if (key == null)
  83. {
  84. algorithm = type switch
  85. {
  86. HashType.SHA1 => new SHA1Managed(),
  87. HashType.SHA256 => new SHA256Managed(),
  88. HashType.SHA384 => new SHA384Managed(),
  89. HashType.SHA512 => new SHA512Managed(),
  90. _ => MD5.Create()
  91. };
  92. }
  93. else
  94. {
  95. algorithm = type switch
  96. {
  97. HashType.SHA1 => new HMACSHA1(key),
  98. HashType.SHA256 => new HMACSHA256(key),
  99. HashType.SHA384 => new HMACSHA384(key),
  100. HashType.SHA512 => new HMACSHA512(key),
  101. _ => new HMACMD5(key)
  102. };
  103. }
  104. return algorithm.ComputeHash(bytes);
  105. }
  106. finally
  107. {
  108. algorithm.Dispose();
  109. }
  110. }
复制代码

使用 示比方 下:

  1. HashHelper.GetHashedBytes(HashType.MD5, "test");
  2. HashHelper.GetHashedBytes(HashType.MD5, "test".GetBytes());
  3. HashHelper.GetHashedBytes(HashType.MD5, "test", "testKey");
  4. HashHelper.GetHashedBytes(HashType.MD5, "test".GetBytes(), "testKey".GetBytes());
  5. HashHelper.GetHashedString(HashType.MD5, "test");
  6. HashHelper.GetHashedString(HashType.SHA1, "test".GetBytes());
  7. HashHelper.GetHashedString(HashType.SHA256, "test", "testKey");
  8. HashHelper.GetHashedString(HashType.MD5, "test".GetBytes(), "testKey".GetBytes());
复制代码

New API Sample

有了新的 API 以后可以怎么简化呢,来看下面的示例:

  1. var bytes = "test".GetBytes();
  2. var keyBytes = "test-key".GetBytes();
  3. // HMACMD5
  4. var hmd5V1 = HMACMD5.HashData(keyBytes, bytes);
  5. var hmd5V2 = HashHelper.GetHashedBytes(HashType.MD5, bytes, keyBytes);
  6. Console.WriteLine(hmd5V2.SequenceEqual(hmd5V1));
  7. // HMACSHA1
  8. var hsha1V1 = HMACSHA1.HashData(keyBytes, bytes);
  9. var hsha1V2 = HashHelper.GetHashedBytes(HashType.SHA1, bytes, keyBytes);
  10. Console.WriteLine(hsha1V2.SequenceEqual(hsha1V1));
  11. // HMACSHA256
  12. var hsha256V1 = HMACSHA256.HashData(keyBytes, bytes);
  13. var hsha256V2 = HashHelper.GetHashedBytes(HashType.SHA256, bytes, keyBytes);
  14. Console.WriteLine(hsha256V2.SequenceEqual(hsha256V1));
  15. // HMACSHA384
  16. var hsha384V1 = HMACSHA384.HashData(keyBytes ,bytes);
  17. var hsha384V2 = HashHelper.GetHashedBytes(HashType.SHA384, bytes, keyBytes);
  18. Console.WriteLine(hsha384V2.SequenceEqual(hsha384V1));
  19. // HMACSHA512
  20. var hsha512V1 = HMACSHA512.HashData(keyBytes ,bytes);
  21. var hsha512V2 = HashHelper.GetHashedBytes(HashType.SHA512, bytes, keyBytes);
  22. Console.WriteLine(hsha512V2.SequenceEqual(hsha512V1));
复制代码

直接使用 对应的 HMAC 哈希算法的 HashData 方法即可,传入对应的 key 和 原始内容就可以了,上面是和我们 HashHelper 封装的方法举行 对比,看效果 是否划一 ,都是划一 的,输出效果 如下:

.NET6中哈希算法的简化用法的实现

More

对于平凡 的哈希算法,微软着实 在 .NET 5 就已经支持了上面的用法,可以尝试一下下面的代码:

  1. var bytes = "test".GetBytes();
  2. // MD5
  3. var md5V1 = MD5.HashData(bytes);
  4. var md5V2 = HashHelper.GetHashedBytes(HashType.MD5, bytes);
  5. Console.WriteLine(md5V2.SequenceEqual(md5V1));
  6. // SHA1
  7. var sha1V1 = SHA1.HashData(bytes);
  8. var sha1V2 = HashHelper.GetHashedBytes(HashType.SHA1, bytes);
  9. Console.WriteLine(sha1V2.SequenceEqual(sha1V1));
  10. // SHA256
  11. var sha256V1 = SHA256.HashData(bytes);
  12. var sha256V2 = HashHelper.GetHashedBytes(HashType.SHA256, bytes);
  13. Console.WriteLine(sha256V2.SequenceEqual(sha256V1));
  14. // SHA384
  15. var sha384V1 = SHA384.HashData(bytes);
  16. var sha384V2 = HashHelper.GetHashedBytes(HashType.SHA384, bytes);
  17. Console.WriteLine(sha384V2.SequenceEqual(sha384V1));
  18. // SHA512
  19. var sha512V1 = SHA512.HashData(bytes);
  20. var sha512V2 = HashHelper.GetHashedBytes(HashType.SHA512, bytes);
  21. 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 哈希算法内容请搜刮 脚本之家从前 的文章或继续欣赏 下面的干系 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 天蝎孤星等 | 2021-9-15 23:41:28 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,他卖的服务器是永久的,我们的网站用 服务器都是在这家买的,你可以去试试。访问地址:http://fwq.mxswl.com
回复

使用道具 举报

avatar 风男人1984 | 2021-9-16 15:15:56 | 显示全部楼层
admin楼主写的很经典!
回复

使用道具 举报

avatar 塔米酉 | 2021-9-19 10:31:03 | 显示全部楼层
admin楼主的帖子实在是写得太好了。文笔流畅,修辞得体!
回复

使用道具 举报

avatar 爰无悔2017 | 2021-9-19 13:31:21 | 显示全部楼层
好东西,学习学习!
回复

使用道具 举报

avatar 聚雅阁砚堂 | 2021-9-20 04:40:31 | 显示全部楼层
终于看完了,很不错!
回复

使用道具 举报

avatar 123457333 | 2021-9-21 14:16:15 | 显示全部楼层
看帖不回帖都是耍流氓!
回复

使用道具 举报

avatar 康乃馨老太 | 2021-9-21 17:41:51 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,他卖的服务器是永久的,我们的网站用 服务器都是在这家买的,你可以去试试。访问地址:http://fwq.mxswl.com
回复

使用道具 举报

avatar 历史人物费 | 2021-9-27 09:07:12 | 显示全部楼层
以后就跟admin楼主混了!
回复

使用道具 举报

avatar jiaguangqin | 2021-9-29 10:11:25 | 显示全部楼层
感谢admin楼主的推荐!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则