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

 更新时间:2021-09-22 21:44:56   作者:佚名   我要评论(0)

目录Intro
New API
Sample Before
New API Sample
More
ReferencesIntro


微软在 .NET 6 中引入一些更简单的 API 来使用 HMAC 哈希算

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中哈希算法的简化用法的实现的文章就介绍到这了,更多相关.NET 6 哈希算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
  • .NET 6 中的隐式命名空间引用
  • CefSharp v62修改方法(支持.net4.0)
  • ASP.NET Core项目配置教程(6)
  • ASP.NET Core部署前期准备 使用Hyper-V安装Ubuntu Server 16.10
  • ASP.NET MVC5+EF6+EasyUI 后台管理系统(81)-数据筛选(万能查询)实例
  • ASP.NET MVC异步获取和刷新ExtJS6 TreeStore
  • ASP.NET MVC5+EF6+EasyUI后台管理系统 微信公众平台开发之资源环境准备
  • ASP.NET MVC5+EF6+EasyUI后台管理系统 微信公众平台开发之消息管理
  • .NET 6 即将到来的新特性 隐式命名空间引用

相关文章

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

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

    目录Intro New API Sample Before New API Sample More ReferencesIntro 微软在 .NET 6 中引入一些更简单的 API 来使用 HMAC 哈希算
    2021-09-22
  • 理解ASP.NET Core 启动类(Startup)

    理解ASP.NET Core 启动类(Startup)

    目录准备工作:一份ASP.NET Core Web API应用程序Startup类Startup构造函数ConfigureServicesConfigure省略Startup类IStartupFilterIHosting
    2021-09-22
  • ASP.NET session.timeout设置案例详解

    ASP.NET session.timeout设置案例详解

    session.timeout 方法一: asp.net Session的默认时间设置是20分钟,即超过20分钟后,服务器会自动放弃Session信息. 当我们在asp.net程序中打开
    2021-09-22
  • C# 有关Assembly.Unload详解

    C# 有关Assembly.Unload详解

    &#160;&#160;&#160;&#160;CLR&#160;产品单元经理(Unit&#160;Manager)&#160;Jason&#160;Zander&#160;在前几天一篇文章&#160;Why&#160;isn't&#
    2021-09-22
  • .Net中异步任务的取消和监控的具体实现

    .Net中异步任务的取消和监控的具体实现

    目录相关类型: CancellationTokenSource CancellationToken 代码示例 思考关联令牌 CancellationChangeToken 相关类型: Can
    2021-09-22
  • ASP.NET Core如何注入多个服务实现类

    ASP.NET Core如何注入多个服务实现类

    目录1、定义个接口2、注入服务 3、功能类 4、高级类前言: 依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体
    2021-09-22
  • python实战之Scrapy框架爬虫爬取微博热搜

    python实战之Scrapy框架爬虫爬取微博热搜

    前言:大概一年前写的,前段时间跑了下,发现还能用,就分享出来了供大家学习,代码的很多细节不太记得了,也尽力做了优化。 因为毕竟是微
    2021-09-22
  • java进阶解析Springboot上传excel存入数据库步骤

    java进阶解析Springboot上传excel存入数据库步骤

    目录一、导入依赖二、前端实现三、后台逻辑三、页面效果 四、可能会遇到的问题 一、导入依赖 这里还是用了Apache的POI插件,现在一般的spr
    2021-09-22
  • C++ com编程学习详解

    C++ com编程学习详解

    目录COM简介COM 规范首先创建一个ATL工程,创建后你会看到一个idl文件COM 原理学习ActiveX总结COM简介 COM全程为component object model ,是
    2021-09-22
  • java random.nextInt的坑及解决

    java random.nextInt的坑及解决

    目录java random.nextInt的坑很简单的两句代码,需要注意两点java random.nextInt()不随机性这个题在网上已经有很多人给出了答案我的算法是验
    2021-09-22

最新评论