幸运赛车赛马游艇游戏开发逻辑分析
Hash,一般翻译做散列,或音译为哈希,普遍将其称之为散列函数,是把任意长度的输入(又叫做预映射 pre-image)哈希算法的处理,转变为固定长度的输出,则输出的数据就可称之为散列值,或称之为哈希值。这种转换是一种压缩映射,也就是一种合理压缩的过程,输出的哈希值所占用的空间远小于输入的空间,但不同的输入可能会散列成相同的输出,换言之,输出值是唯一的,但无法找寻与其一一对应的输入值。
项目开发咨询薇芯 hkkf5566
由于散列函数应用的多样性,它们经常是专为某一应用而设计的。
错误校验
使用一个散列函数可以很直观地检测出数据在传输时发生的错误。在数据的发送方,将散列函数应用于未发送的数据中,并将计算结果和原始数据一同发送。那么,在数据的接收方,将接收到的数据利用相同的散列函数进行处理,如果两次散列函数计算出来的结果不同,那么就说明数据在传输的过程中出现了差错。这就叫做冗余校验。
信息安全
Hash 算法是现代密码体系中保密程度最高的一种方式。由于非对称算法既费时又费力的弊端,所以在数字签名协议中,单向散列函数完全的取代了传统的加密方式。
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));
评论