简体   繁体   中英

Unsuccessful verifying (C# .NET HMACSHA256 Class)

I'm trying to learn the .NET API and I created a program that compares the key in the source file with a key from an XML file.

I used the following exaple (the third method for varifying a document:

https://docs.microsoft.com/en-gb/dotnet/api/system.security.cryptography.hmacsha256?view=netframework-4.7.1

Right now my program runs but it always says that the files have been tampered with even though I am absolutely sure that they are not since I have just created them.

Here is my code:

VerifyDocument.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Xml.Serialization;

public class VerifyDocument
{

public static void Main(string[] args)
{

XmlSerializer xml = new XmlSerializer(typeof(byte[]));
byte[] key;
string keyFile = args[1];
string sourceFile = args[0];
using (StreamReader reader = new StreamReader(keyFile)) {
  key = (byte[]) xml.Deserialize(reader);
}

bool err = false;

        using (HMACSHA256 hmac = new HMACSHA256(key)) // Initialize the keyed hash object.
        {

            byte[] storedHash = new byte[hmac.HashSize / 8]; // Create an array to hold the keyed hash value read from the file.

            using (FileStream inStream = new FileStream(sourceFile, FileMode.Open)) // Create a FileStream for the source file.
            {

                inStream.Read(storedHash, 0, storedHash.Length); // Read in the storedHash.

                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!");

        }
        else
        {
            Console.WriteLine("Hash values agree -- no tampering occurred.");

        }

}

}

SignDocument.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Xml.Serialization;

public class HMACSHA256example
{    

   public static void Main(string[] args)
  {


    if (args.Length != 2) {
      Console.WriteLine("Usage: [mono] SignDocument.exe <filename> <key>");
      Environment.Exit(1);
    } else
    {
      XmlSerializer xml = new XmlSerializer(typeof(byte[]));
      byte[] key;
      string keyFile = args[1];
      string sourceFile = args[0];
      string destFile = sourceFile + ".hash";
      using (StreamReader reader = new StreamReader(keyFile)) {
        key = (byte[]) xml.Deserialize(reader);
      }

      using (HMACSHA256 hmac = new HMACSHA256(key)) // Initialize the keyed hash object.
      {
          using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
          {
              using (FileStream outStream = new FileStream(destFile, FileMode.Create))
              {

                  byte[] hashValue = hmac.ComputeHash(inStream); // Compute the hash of the input file.


                  outStream.Write(hashValue, 0, hashValue.Length); // Write the computed hash value to the output file.

          }
      }

    }

 }
 }
 }

CreateKey.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Xml.Serialization;

namespace COMP3911.Crypto {


class CreateKey {
static void Main(string[] args) {

  string input;

  if (args.Length == 0) {
    Console.WriteLine("Usage: [mono] CreateKey.exe <filename>");
    Environment.Exit(1);
  }

  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);
        }


  // XML
  string keyfile = args[0] + ".key";
  using (StreamWriter output = new StreamWriter(keyfile, false)) {
    XmlSerializer xml = new XmlSerializer(typeof(byte[]));
    xml.Serialize(output, secretkey);
  }
}
}

}

ANY HELP would be greatly appreciated !

Your "sign" program reads inStream and writes just the HMAC to outStream .

Your "verify" program reads a file and expects that it is the HMAC followed by the data.

Either "sign" needs to rewind inStream and then copy it into outStream or you need to change "verify" to look at the two files independently.

SignDocument.cs has the error. You're writing the signature but failing to write the rest of the file.

It should be something like this (mostly copied from the documentation page you linked to):

using (HMACSHA256 hmac = new HMACSHA256(key)) // Initialize the keyed hash object.
{
    using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
    {
        using (FileStream outStream = new FileStream(destFile, FileMode.Create))
        {
            byte[] hashValue = hmac.ComputeHash(inStream); // Compute the hash of the input file.
            outStream.Write(hashValue, 0, hashValue.Length); // Write the computed hash value to the output file.

            inStream.Position = 0;
            int bytesRead;
            byte[] buffer = new byte[1024];
            do
            {
                bytesRead = inStream.Read(buffer, 0, 1024);
                outStream.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);

        }
    }
}

UPDATE

Not sure why the MSDN version doesn't use CopyTo , but seems better:

byte[] hashValue = hmac.ComputeHash(inStream);
outStream.Write(hashValue, 0, hashValue.Length);

inStream.Position = 0;
inStream.CopyTo(outStream);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM