下面的示例演示如何使用 HMACSHA256 对象,然后验证文件的方法来对文件进行签名。
C#
using System; using System.IO; using System.Security.Cryptography;
public class HMACSHA256example {
public static void Main(string[] Fileargs) { string dataFile; string signedFile; //If no file names are specified, create them. if (Fileargs.Length < 2) { dataFile = @"text.txt"; signedFile = "signedFile.enc";
if (!File.Exists(dataFile)) { // Create a file to write to. using (StreamWriter sw = File.CreateText(dataFile)) { sw.WriteLine("Here is a message to sign"); } } } else { dataFile = Fileargs[0]; signedFile = Fileargs[1]; } try { // Create a random key using a random number generator. This would be the // secret key shared by sender and receiver. byte[] secretkey = new Byte[64]; //RNGCryptoServiceProvider is an implementation of a random number generator. using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) { // The array is now filled with cryptographically strong random bytes. rng.GetBytes(secretkey);
// Use the secret key to sign the message file. SignFile(secretkey, dataFile, signedFile);
// Verify the signed file VerifyFile(secretkey, signedFile); } } catch (IOException e) { Console.WriteLine("Error: File not found", e); } } //end main // Computes a keyed hash for a source file and creates a target file with the keyed hash // prepended to the contents of the source file. public static void SignFile(byte[] key, String sourceFile, String destFile) { // Initialize the keyed hash object. using (HMACSHA256 hmac = new HMACSHA256(key)) { using (FileStream inStream = new FileStream(sourceFile, FileMode.Open)) { using (FileStream outStream = new FileStream(destFile, FileMode.Create)) { // Compute the hash of the input file. byte[] hashValue = hmac.ComputeHash(inStream); // Reset inStream to the beginning of the file. inStream.Position = 0; // Write the computed hash value to the output file. outStream.Write(hashValue, 0, hashValue.Length); // Copy the contents of the sourceFile to the destFile. int bytesRead; // read 1K at a time byte[] buffer = new byte[1024]; do { // Read from the wrapping CryptoStream. bytesRead = inStream.Read(buffer, 0, 1024); outStream.Write(buffer, 0, bytesRead); } while (bytesRead > 0); } } } return; } // end SignFile
// Compares the key in the source file with a new key created for the data portion of the file. If the keys // compare the data has not been tampered with. public static bool VerifyFile(byte[] key, String sourceFile) { bool err = false; // Initialize the keyed hash object. using (HMACSHA256 hmac = new HMACSHA256(key)) { // Create an array to hold the keyed hash value read from the file. byte[] storedHash = new byte[hmac.HashSize / 8]; // Create a FileStream for the source file. using (FileStream inStream = new FileStream(sourceFile, FileMode.Open)) { // Read in the storedHash. inStream.Read(storedHash, 0, storedHash.Length); // Compute the hash of the remaining contents of the file. // The stream is properly positioned at the beginning of the content, // immediately after the stored hash value. byte[] computedHash = hmac.ComputeHash(inStream); // compare the computed hash with the stored value
for (int i = 0; i < storedHash.Length; i++) { if (computedHash[i] != storedHash[i]) { err = true; } } } } if (err) { Console.WriteLine("Hash values differ! Signed file has been tampered with!"); return false; } else { Console.WriteLine("Hash values agree -- no tampering occurred."); return true; } } //end VerifyFile } //end class
注解 HMACSHA256 是一种加密哈希算法,它是从 SHA-256 哈希函数构建的,用作基于哈希的消息验证代码(HMAC)。 HMAC 进程将密钥与消息数据混合,使用哈希函数对结果进行哈希运算,再次混合使用密钥的哈希值,然后再次应用哈希函数。 输出哈希的长度为256位。
如果发送方和接收方共享密钥,则可以使用 HMAC 来确定通过不安全通道发送的消息是否已被篡改。 发件人计算原始数据的哈希值,并以单个消息形式发送原始数据和哈希值。 接收方重新计算收到的消息上的哈希值,并检查计算的 HMAC 是否与传输的 HMAC 匹配。
对数据或哈希值所做的任何更改都将导致不匹配,因为更改消息和重现正确的哈希值需要使用机密密钥知识。 因此,如果原始和计算所得的哈希值匹配,则将对消息进行身份验证。
HMACSHA256 接受任意大小的密钥,并产生长度为256位的哈希序列。