Hash是一种将任意长度的数据转换为固定长度的数字值的算法,也称为散列或摘要。Hash可以用于确保数据的完整性,验证数字签名,生成密码等场景。在.NET Core中,有多种类型和用法的Hash算法,本文将介绍其中一些常见的例子。
一、使用System.Security.Cryptography命名空间下的类生成和验证Hash
.NET Core提供了System.Security.Cryptography命名空间下的一系列类来支持不同类型的Hash算法,例如SHA1, SHA256, SHA384, SHA512, MD5等。这些类都实现了抽象基类HashAlgorithm,因此具有相同的基本方法和属性。例如:
HashData(byte[] data):接受一个字节数组作为参数,返回一个字节数组作为Hash值。
ComputeHash(Stream inputStream):接受一个流对象作为参数,返回一个字节数组作为Hash值。
ComputeHash(byte[] buffer):接受一个字节数组作为参数,返回一个字节数组作为Hash值。
ComputeHash(byte[] buffer, int offset, int count):接受一个字节数组、偏移量和长度作为参数,返回一个字节数组作为Hash值。
要使用这些类生成和验证Hash值,可以按照以下步骤进行:
创建一个对应类型的对象实例,例如SHA256 sha256 = SHA256.Create();
调用其中一个ComputeHash方法或者静态方法HashData来获取数据的Hash值,并将其转换为十六进制字符串或其他格式方便存储或传输。
在需要验证数据完整性时,再次对数据进行相同类型和方式的哈希运算,并与之前存储或传输的哈希值进行比较。如果两者相同,则说明数据没有被篡改;如果不同,则说明数据已经被修改。
以下是一个使用SHA256对字符串进行哈希运算并验证其完整性的示例代码:
using System;
using System.Text;
using System.Security.Cryptography;
classProgram
{
staticvoidMain(string[] args)
{
//原始字符串string originalString = "Hello world!";
//将字符串转换为字节数组byte[] originalBytes = Encoding.UTF8.GetBytes(originalString);
//创建SHA256对象实例
SHA256 sha256 = SHA256.Create();
//计算原始字符串的哈希值,并转换为十六进制字符串byte[] hashBytes = sha256.ComputeHash(originalBytes);
string hashString = Convert.ToHexString(hashBytes);
Console.WriteLine($"The hash value of {originalString} is {hashString}");
//模拟修改原始字符串string modifiedString = "Hello World!";
byte[] modifiedBytes = Encoding.UTF8.GetBytes(modifiedString);
//计算修改后字符串的哈希值,并转换为十六进制字符串byte[] modifiedhashBytes = sha256.ComputeHash(modifiedBytes);
string modifiedhashString = Convert.ToHexString(modifiedhashBytes);
//比较两个哈希值是否相同if (hashString == modifiedhashString)
Console.WriteLine("The data has not been altered.");
else
Console.WriteLine("The data has been altered.");
}
}
输出结果如下:
The hash value of Hello world! is A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E
The data has been altered.
二、使用System.HashCode结构体生成和验证非加密型散列码
除了上述加密型散列码外,在.NET Core中还有一种非加密型散列码(non-cryptographic hash code)的结构体System.HashCode,它可以用于生成一个32位或64位的散列码,用于快速比较数据的相等性或者作为哈希表的键值。System.HashCode不适用于加密场景,因为它不是安全的,也不是稳定的(在不同的运行时或平台上可能产生不同的结果)。要使用System.HashCode生成和验证散列码,可以按照以下步骤进行:
创建一个System.HashCode对象实例,并调用其中的Add方法来添加数据。Add方法可以接受各种类型的参数,例如int, string, bool等,并且可以链式调用。
调用其中的ToHashCode方法来获取一个32位或64位(取决于平台)的散列码,并将其转换为十六进制字符串或其他格式方便存储或传输。
在需要验证数据完整性时,再次对数据进行相同方式的哈希运算,并与之前存储或传输的哈希值进行比较。如果两者相同,则说明数据没有被篡改;如果不同,则说明数据已经被修改。
以下是一个使用System.HashCode对字符串进行哈希运算并验证其完整性的示例代码:
using System;
classProgram
{
staticvoidMain(string[] args)
{
//原始字符串string originalString = "Hello world!";
//创建HashCode对象实例,并添加原始字符串
HashCode hashCode = new HashCode();
hashCode.Add(originalString);
//计算原始字符串的哈希值,并转换为十六进制字符串int hashValue = hashCode.ToHashCode();
string hashString = hashValue.ToString("X");
Console.WriteLine($"The hash value of {originalString} is {hashString}");
//模拟修改原始字符串string modifiedString = "Hello World!";
//创建HashCode对象实例,并添加修改后字符串
HashCode modifiedhashCode = new HashCode();
modifiedhashCode.Add(modifiedString);
//计算修改后字符串的哈希值,并转换为十六进制字符串int modifiedhashValue = modifiedhashCode.ToHashCode();
string modifiedhashString = modifiedhashValue.ToString("X");
//比较两个哈希值是否相同if (hashString == modifiedhashString)
Console.WriteLine("The data has not been altered.");
else
Console.WriteLine("The data has been altered.");
}
}
输出结果如下:
The hash value of Hello world! is 7F5B54CE
The data has been altered.
三、使用System.Buffers.Text.Base64类对字节数组进行Base64编码和解码
Base64是一种将二进制数据转换为可打印字符(ASCII)格式的编码方式,常用于在文本协议中传输二进制数据。Base64编码后会使原始数据长度增加约33%,但是可以保证在任何环境下都能正确传输和解析。在.NET Core中,有多种方式可以对字节数组进行Base64编码和解码,例如使用Convert类或者Encoding类。本文将介绍一种新引入.NET Core 2.1版本中的类:System.Buffers.Text.Base64,它提供了更高效和灵活地处理Base64编码和解码。
要使用System.Buffers.Text.Base64类对字节数组进行Base64编码和解码,可以按照以下步骤进行:
创建一个字节数组作为源数据,例如byte[] sourceBytes = Encoding.UTF8.GetBytes(“Hello world!”);
调用其中静态方法TryEncodeToUtf8来将源字节数组转换为Base64编码后的字节数组,并指定目标数组、是否插入换行符、是否填充占位符等参数。TryEncodeToUtf8方法会返回一个bool值表示是否成功编码,并通过out参数返回编码后的字节数组长度。 4. 调用其中静态方法TryDecodeFromUtf8来将Base64编码后的字节数组转换为原始字节数组,并指定目标数组等参数。TryDecodeFromUtf8方法会返回一个bool值表示是否成功解码,并通过out参数返回解码后的字节数组长度。 5. 在需要验证数据完整性时,再次对数据进行相同方式的Base64编码或解码,并与之前存储或传输的数据进行比较。如果两者相同,则说明数据没有被篡改;如果不同,则说明数据已经被修改。
以下是一个使用System.Buffers.Text.Base64类对字节数组进行Base64编码和解码并验证其完整性的示例代码:
using System;
using System.Text;
using System.Buffers.Text;
classProgram
{
staticvoidMain(string[] args)
{
//原始字符串string originalString = "Hello world!";
//将字符串转换为字节数组byte[] originalBytes = Encoding.UTF8.GetBytes(originalString);
//创建一个足够大的目标数组用于存储Base64编码后的字节数组byte[] encodedBytes = newbyte[originalBytes.Length * 2];
//调用TryEncodeToUtf8方法将原始字节数组转换为Base64编码后的字节数组,不插入换行符,不填充占位符bool encodeSuccess = Base64.TryEncodeToUtf8(originalBytes, encodedBytes, outint encodedLength, false);
//判断是否成功编码,并将结果输出到控制台if (encodeSuccess)
Console.WriteLine($"The Base64 encoded value of {originalString} is {Encoding.UTF8.GetString(encodedBytes)}");
else
Console.WriteLine("Failed to encode.");
//模拟修改原始字符串string modifiedString = "Hello World!";
byte[] modifiedBytes = Encoding.UTF8.GetBytes(modifiedString);
//创建一个足够大的目标数组用于存储Base64编码后的字节数组byte[] modifiedEncodedBytes = newbyte[modifiedBytes.Length * 2];
//调用TryEncodeToUtf8方法将修改后的字节数组转换为Base64编码后的字节数组,不插入换行符,不填充占位符bool modifiedEncodeSuccess = Base64.TryEncodeToUtf8(modifiedBytes, modifiedEncodedBytes, outint modifiedEncodedLength, false);
//比较两个Base64编码后的字节数组是否相同if (encodeSuccess && modifiedEncodeSuccess && encodedLength == modifiedEncodedLength)
Console.WriteLine("The data has not been altered.");
else
Console.WriteLine("The data has been altered.");
}
}
输出结果如下:
The Base64 encoded value of Hello world! is SGVsbG8gd29ybGQh
The data has been altered.