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

.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iis 404错误从定向完美方案

is 404错误从定向完美方案 自定义404页 面返回不当状态码如“200”等给网站最终SEO效果带来的不利影响&#xff0c;因此&#xff0c;确保自定义的404错误页面能够返回“404” 状态码是极为重要的&#xff0c;也是网站优化与SEO的基本要求。 HTTP404对 SEO的影响   自定义404错…

python 百度百科 爬虫_python简单爬虫

爬虫真是一件有意思的事儿啊&#xff0c;之前写过爬虫&#xff0c;用的是urllib2、BeautifulSoup实现简单爬虫&#xff0c;scrapy也有实现过。最近想更好的学习爬虫&#xff0c;那么就尽可能的做记录吧。这篇博客就我今天的一个学习过程写写吧。 一 正则表达式 正则表达式是一个…

知乎上这个程序员火了,竟是因为给老板修了一 次U盘

全世界只有3.14 % 的人关注了爆炸吧知识相信很多小伙伴曾经遇到这样的问题软件工程▼知识君陷入沉思都说知乎出人才&#xff0c;于是知识君飞赴知乎希望能得到广大网友的点拨&#xff01;知乎上有位朋友就分享了他的经验做为一名全栈程序员居然要我修电脑。你以为我会和领导说告…

mysql 批量_mysql LOAD语句批量录入数据

本章的前面讨论如何使用SQL向一个表中插入数据。但是&#xff0c;如果你需要向一个表中添加许多条记录&#xff0c;使用SQL语句输入数据是很不方便的。幸运的是&#xff0c;MySQL提供了一些方法用于批量录入数据&#xff0c;使得向表中添加数据变得容易了。本节以及下一节&…

VS2010 NDoc的插件工具

1、下载Sandcastle Help File Builder&#xff1a; http://www.codeplex.com/SHFB 2、下载sandcastle&#xff1a; http://www.microsoft.com/downloads/details.aspx?FamilyIDe82ea71d-da89-42ee-a715-696e3a4873b2&DisplayLangen 1、先安装sandcastle&#xff0c;然后安…

回到校园

最近一段时间&#xff0c;作息时间调整的原因&#xff0c;有了周六&#xff0c;周日。今天是星期六&#xff0c;下午没有什么事情&#xff0c;就带了本书&#xff0c;重新回到毕业5年的大学&#xff0c;又去上了一节自习&#xff01;上学的感觉很好呀~~~转载于:https://blog.51…

Abel 分部求和法

本文之所以叫Abel分部求和法而不叫Abel分部求和公式&#xff0c;是因为求和公式有可能形式上有所不同&#xff0c;但是方法确实相同的。 $$\sum_{nM}^{N}a_{n}b_{n} \sum_{nM}^{N} a_{n}B_{n}-\sum_{nM}^{N}a_{n}B_{n-1}$$ 而 $$\sum_{nM}^{N}a_{n}B_{n-1}\sum_{M-1}^{N-1}a_{…

使用Pitcher简化卫语句

什么是卫语句在方法的开头&#xff0c;我们经常会添加一些检查代码&#xff0c;当检查条件为true时立刻从方法中返回。这样的单独检查代码被称为“卫语句”。例如&#xff0c;我们在添加用户时会检查用户名不能为空&#xff0c;年龄必须大于0&#xff1a;public void AddUser(s…

男人的本质需求

1 新的一天也要保持微笑哦2 别拍了&#xff01;快救我&#xff01;3 被可爱到了4 通过薯条学习骨折的分类。从左向右依次是&#xff1a;螺旋骨折、斜向骨折、横向骨折、多段骨折和粉碎性骨折。5 高级玩家啊~6 男人的本质需求你点的每个赞&#xff0c;我都认真当成了喜欢

python小甲鱼爬虫妹子_【Python学习日记】B站小甲鱼:爬虫

Web Spider Python 如何访问互联网 URL lib -->urllib URL的一般格式为 protocol://hostname[:port] / /path /[;parameters][?query]#fragment&#xff0c;其中[]为可选项 URL由三部分组成 第一部分是协议 第二部分是存放资源的服务器的域名系统或IP地址&#xff08;有时…

【转】了解SQL Server触发器及触发器中的事务

引述 首先&#xff0c; 说下我写篇文章的目的&#xff0c;我希望能把我对触发器的理解&#xff0c;分享出来与你一起学习。如果你有对触发器和事务的概念&#xff0c;有些了解&#xff0c;这篇文章&#xff0c;对你来说会是很简单&#xff0c;或能让你更进一步的了解触发器里面…

Java将mysql输出csv_使用Java将大量数据从数据库导出到.csv时出...

我,谢谢您的关注.我想使用Java将大量数据,实际上是大量数据(600万行)导出到.csv文件.该应用程序是使用toplink(ojdbc14)的JPA摆动应用程序.我尝试使用&#xff1a;但是BufferedWriterRandomAccessFile的FileChannel等等,但是尽管我将最大堆大小设置为800m(-Xmx800m),但是内存消…

Oracle interview

Oracle Applications General Questions How can you restrict the access (to oracle apps) to A GROUP OF users using personalization?How do you enable trace/debug in APPS?What are custom events in apps and how to you enable/disable it?What is diagnostics in…

ASP.Net Core Web API 如何返回 File。

咨询区 Jan Kruse&#xff1a;我想在 ASP.Net Web API 中返回 File 文件&#xff0c;我目前的做法是将 Action 返回值设为 HttpResponseMessage&#xff0c;参考代码如下&#xff1a;public async Task<HttpResponseMessage> DownloadAsync(string id) {var response ne…

python导包路径问题_python的导包问题

有事会遇到在python代码中导入包错误问题&#xff0c;本文简单对python包的引入做简单介绍 简单说,我认为python导包一共有3种情况,分别是: 要导的包与当前文件在同一层 要导的包在当前文件的底层(就是与当前文件夹同级的文件夹里) 要导的包在当前文件的上层 1、要导的包与当前…

垃圾代码还能出圈?手把手教你写垃圾代码,从入门到精通!

全世界只有3.14 % 的人关注了爆炸吧知识转自&#xff1a;机器之心参与&#xff1a;思如果说到什么是好代码&#xff0c;我们肯定都能说出一堆规则&#xff0c;例如使用一致的格式和缩进、使用清晰的变量名和方法名、在必要时提供文档与注释、不要过度精简代码等等。但是对于什么…

winform能连MySQL吗_c# winform中怎么连接mysql

匿名用户1级2018-11-19 回答static string myConnstr "serverip;user idroot; passwordpasswd;databasedb;poolingfalse;charsetgbk;";//System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls false;public static MySqlConnection GetMyConnection(){My…

User Experience Kit

User Experience Kit&#xff08;UEK&#xff09; 是微软官方发布的&#xff0c;集成了有关如何使用 Silverlight 3, Silverlight 4 实现有关媒体发布、数字化营销、以及使用 Silverlight 构建客户端的最新案例、白皮书以及部分源码。从这里下载 UEK 的概览. 网站地址&#xff…

java以Blob形式存储,读取图片并在jsp页面显示图片流

2019独角兽企业重金招聘Python工程师标准>>> 废话少说代码伺候&#xff1a; 封装好的ImageUtil类&#xff1a;目的读取本地的图片文件并存入数据库&#xff0c;然后读出数据库中以Blob形式存储的图片保存到指定目录。 1 package org.blog.util; 2 import java.io.F…

“ShardingCore”是如何针对分表下的分页进行优化的

首先还是要给自己的开原框架打个广告 sharding-core 针对efcore 2版本的分表组件&#xff0c;首先我们来快速回顾下目前市面上分表下针对分页常见的集中解决方案分表解决方案解决方案skip<100skip<10000skip>10000优点缺点内存分表速度快O(n)&#xff0c;nskip*分表数…