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

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 定义如下:

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));

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

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 中哈希算法的简化用法相关推荐

  1. 区块链中哈希算法c语言代码,解析区块链中的核心技术哈希(Hash)算法

    原标题:解析区块链中的核心技术哈希(Hash)算法 作者:崔利民 区块链是分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.区块链的关键技术组成主要为:P2P网络协议.共识机制 ...

  2. sha算法 哈希算法_SHA1哈希算法教程及其用法示例

    sha算法 哈希算法 SHA1 is a hash algorithm that is created by the National Security Agency (NSA). SHA1 hash ...

  3. C#中哈希表(HashTable)的用法详解

    1.  哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对, ...

  4. HashMap中的hash算法的几个思考

    HashMap中哈希算法的关键代码 //重新计算哈希值 static final int hash(Object key) {int h;return (key == null) ? 0 : (h = ...

  5. 计算机视觉的几个经典算法 —— 最小二乘法 + RANSAC + 哈希算法(附DCT) + 图像聚类算法

    计算机视觉的几个经典算法 目录 计算机视觉的几个经典算法 1. 最小二乘法(寻找线性回归函数) 2. RANSAC(模型已知,参数未知) 2.1 RANSAC 与 最小二乘法的区别 2.2 RANSA ...

  6. 区块链 01(简化后的区块包括父区块哈希值、数据、时间戳、哈希值这四个字段,区块的哈希值由父区块哈希值、数据、时间戳、3个字段拼接通过 哈希算法计算而成)

    """区块包括区块头和区块体两个部分.区块头由版本.父区块哈希值.数据.Merkle根.时间戳.目标难度. #Nonce值组成:区块体实际上可以包含任何内容,在比特币中包 ...

  7. MATLAB中计算图像哈希,数字图像处理算法及原理(三):相似图片搜索(平均哈希算法)...

    这里的关键技术叫做"感知哈希算法(aHash)"ash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同 ...

  8. 一致性哈希算法及其在分布式系统中的应用

    摘要 本文将会从实际应用场景出发,介绍一致性哈希算法(Consistent Hashing)及其在分布式系统中的应用.首先本文会描述一个在日常开发中经常会遇到的问题场景,借此介绍一致性哈希算法以及这个 ...

  9. 区块链课程笔记-第一课哈希算法在加密中的应用

    哈希密码,哈希碰撞的含义,即我们有一个值x经过哈希变换得到y. 输出y是有限的,2的256次幂,但是输入x是无限的.输入值的一点点变动,输出的值都会变动.但是如果输入不同的值,而得到了相同的值,那么就 ...

最新文章

  1. Word中新建样式/修改样式对话框中的各个选项意义
  2. KernelBuildpackageHowto
  3. matlab神经网络每次相差大,GA-BP网络为什么每次训练的结果相差很大呢?
  4. python 模块学习--Numpy
  5. 日均万亿条数据如何处理?爱奇艺实时计算平台这样做
  6. python如何快速导入未安装模块_如何导入安装在sitepackages中的模块
  7. 离线安装IE11浏览器
  8. 最新cs1.6服务器ip地址,CS1.6服务器IP地址
  9. 软工视频-----系统结构图
  10. AHP(层次分析法)学习笔记及多层权重Python实践
  11. 启发式搜索解决八数码难题
  12. 产品思维训练 | 卖菜的店同时也卖水果,卖水果的店为什么不卖菜?
  13. 涂涂乐制作之不得不说的坑
  14. macd指标如何看?怎么用MACD指标确定买入和离场点?
  15. 基于HyperLPR的车牌识别
  16. python go高并发_天下武功为快不破,戏说Python与Go高并发争锋!
  17. Zabbix监控平台部署+监控客户端
  18. Java后端实现安卓/IOS移动端消息推送(百度云推送)
  19. python常用可视化技巧
  20. 缓存穿透和缓存雪崩的一些解决方案

热门文章

  1. GCT之数学公式(三角函数)
  2. 基础设备----笔记
  3. 硬盘分区与故障排解速查手册(1)
  4. SQL Server2008导入导出数据库
  5. spring技术小结
  6. SQL Server 2000详细安装过程及配置
  7. 性能测试一些相关的概念
  8. Java Decompiler(Java反编译工具)
  9. 公众平台关注用户达到5万即可开通流量主功能 可以推广APP应用
  10. Linux PCI 设备驱动基本框架(一)