NET框架中提供了许多Hash类每种算法的实现方式不同但是在使用层面上NET为我们提供了几乎一致的操作所谓一通百通在本节不打算把所有的算法都做演示因为这样既没必要性也鄙视读者的智商
关于SHA我们选用托管实现SHAManaged类做演示在实际应用中我建议各位读者尽可能的使用托管实现因为基于加密服务的实现对特定的操作系统环境有依赖性
代码清单演示了简单的Hash应用将一个字符串散列之后保存散列值然后对字符串做验证操作
代码清单 SHAManaged类的简单应用
class Program
{
static SHAManaged shaM = new SHAManaged();
static void Main(string[] args)
{
string testString = 大家好我是xuanhun欢迎阅读我的文章!;
byte[] hashY = GetHashData(testStringtestString);
string testString = 大家好我是xuanhun欢迎阅读我的文章!;
byte[] hashY = GetHashData(testStringtestString);
string ChangedString = 大家好我是xuanhun欢迎阅读我的文章;
byte[] hashChange = GetHashData(ChangedStringChangedString);
ConsoleRead();
}
private static byte[] GetHashData(string sstring ys)
{
ConsoleWriteLine({}:ys);
byte[] buffer = EncodingUTFGetBytes(s);
byte[]hashBytes= shaMComputeHash(buffer);
OutHash(hashBytes);
return hashBytes;
}
private static void OutHash(byte[] hashBytes)
{
foreach (byte b in hashBytes)
{
ConsoleWrite({} b);
}
ConsoleWriteLine();
ConsoleWriteLine();
}
}
现在我们简单分析代码清单先看GetHashData方法它的主要工作是对传入的字符串s做处理获取它的hash值第一步通过EncodingUTFGetBytes(s)把字符串转成byte数组然后对该byte数组进行散列操作完成操作的是下面这条语句
byte[]hashBytes= shaMComputeHash(buffer)
shaM是SHAManaged的实例这里我们使用ComputeHash方法返回byte数组的Hash值
OutHash方法用来输出散列值
Main方法中我定义了三个字符串第一个和第二个字符串完全一样第三个字符串只少了一个歎号(!)下面我们看一下这段程序的运行结果如图所示
图 代码清单的运行结果
从图中我们很容易看出改掉一个字符hash值发生了很大的变化
在实际应用中为了增强安全性我们更倾向于使用键控HashNET中的每个Hash加密算法都有对应的键控Hash类针对于上个例子我们演示如何使用HMACSHA类实例程序如代码清单所示
代码清单 HMACSHA类应用实例
class Program
{
public static void Encript(byte[] key String sourceFile String destFile)
{
HMACSHA myhmacsha = new HMACSHA(key);
FileStream inStream = new FileStream(sourceFile FileModeOpen);
FileStream outStream = new FileStream(destFile FileModeCreate);
byte[] hashValue = myhmacshaComputeHash(inStream);
inStreamPosition = ;
outStreamWrite(hashValue hashValueLength);
int bytesRead;
byte[] buffer = new byte[];
do
{
bytesRead = inStreamRead(buffer );
outStreamWrite(buffer bytesRead);
} while (bytesRead > );
myhmacshaClear();
inStreamClose();
outStreamClose();
return;
}
public static bool Decript(byte[] key String sourceFile)
{
HMACSHA hmacsha = new HMACSHA(key);
byte[] storedHash = new byte[hmacshaHashSize / ];
FileStream inStream = new FileStream(sourceFile FileModeOpen);
inStreamRead(storedHash storedHashLength);
byte[] computedHash = hmacshaComputeHash(inStream);
for (int i = ; i < storedHashLength; i++)
{
if (computedHash[i] != storedHash[i])
{
ConsoleWriteLine(Hash值验证失败文件被篡改!);
return false;
}
}
ConsoleWriteLine(文件完整!);
return true;
}
public static void Main(string[] Fileargs)
{
string file = @f:\txt;
string file = @f:\txt;
try
{
byte[] secretkey = new Byte[];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rngGetBytes(secretkey);
Encript(secretkey file file);
Decript(secretkey file);
}
catch (IOException e)
{
ConsoleWriteLine(eMessage);
}
ConsoleRead();
}
}
}
看代码清单在Main方法中我定义了file和file两个变量file为本地磁盘的一个已经存在的文件file是未存在的文件将由程序创建下面注意Main方法中的这两句代码
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rngGetBytes(secretkey);
RNGCryptoServiceProvider类提供方法用来生成高强度随机数这里我们用来生成作为HMACSHA类的加密和解密的密钥
Encript方法用来使用HMACSHA类生成文件file的加密Hash值我们首先创建了两个文件流inStream和outStream分别对应file和file然后读取file的内容使用myhmacshaComputeHash方法获取加密的Hash值并将该值写入file
Decript方法用来验证文件完整性验证文件完整性的方法很简单我们读出保存在file中key的Hash数据然后使用之前的Key对该数据执行Hash如果得到的Hash值和取出的KeyHash值相同则数据完整
执行加密Hash的过程后file和file的文件内容如图所示
图 执行加密Hash的过程后file和file的文件内容
从图中我们可以看出加密Hash值被添加在原文内容的前边
验证结果如图所示
图