DotNet Example: Digital Hash
Description
Digital hash functions are often used to validate executable files and digital documents. One important use of a digital hash is to sign e-commerce documents; this is required in order to do business on Amazon, for example.
The .NET Framework has a full set of encryption functions, so it was relatively easy to create a .NET assembly and Xbasic wrapper function for the purpose of implementing an HMAC (hash-based message authentication code).
The value returned for the HMAC hash is in Base64, which is what Amazon wants for e-commerce. If you try to compare Base64 with an online hash calculator that returns hexadecimal, they will not appear to match.
See the Plain SHA-1 Hash section below if you only want a simple SHA1 hash, rather than an encrypted HMAC hash based on SHA1 or another hash algorithm.
The C# code used to create the DLL, "DigitalHash.dll":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace HashLib
{
public class HMAC
{
/// <summary>
/// Computes RFC 2104-compliant HMAC signature
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="algorithm"></param>
/// <returns>Signature</returns>
public String Sign(String data, String key, KeyedHashAlgorithm algorithm)
{
Encoding encoding = new UTF8Encoding();
algorithm.Key = encoding.GetBytes(key);
return Convert.ToBase64String(algorithm.ComputeHash(
encoding.GetBytes(data.ToCharArray())));
}
/// <summary>
/// Computes RFC 2104-compliant HMAC signature using SHA1
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns>Signature</returns>
public String Sign1(String data, String key)
{
KeyedHashAlgorithm algorithm = new HMACSHA1();
return Sign(data, key, algorithm);
}
/// <summary>
/// Computes RFC 2104-compliant HMAC signature using SHA256
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns>Signature</returns>
public String Sign256(String data, String key)
{
KeyedHashAlgorithm algorithm = new HMACSHA256();
return Sign(data, key, algorithm);
}
/// <summary>
/// Computes RFC 2104-compliant HMAC signature using specified signature method
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="SignatureMethod"></param>
/// <returns>Signature</returns>
public String SignUsing(String data, String key, String SignatureMethod)
{
KeyedHashAlgorithm algorithm = KeyedHashAlgorithm.Create(SignatureMethod.ToUpper());
return Sign(data, key, algorithm);
}
}
}The Xbasic module that contains the wrapper function:
FUNCTION HMAC_HASH as C(data as C, key as C, assembly_path as C, algorithm as C = "HMACSHA1")
'debug(1)
dim alg as C = upper(algorithm)
'register .NET class
dim sv as DotNet::Services
dim assembly as DotNet::AssemblyReference
assembly.FileName = assembly_path+"DigitalHash.dll"
IF .not. file.exists(assembly.FileName)
ui_msg_box("File not found",assembly.FileName)
end
END IF
IF sv.RegisterClass("","","HashLib.HMAC",assembly) THEN
'Call appropriate .NET method if registration succeeds
dim hash as DotNet::HashLib::HMAC
SELECT
CASE alg="HMACSHA1"
HMAC_HASH = hash.Sign1(data,key)
CASE alg="HMACSHA256"
HMAC_HASH = hash.Sign256(data,key)
CASE else
HMAC_HASH = hash.SignUsing(data,key,alg)
END SELECT
END IF
END FUNCTION
exports.HMAC_HASH = HMAC_HASHAn interactive session to test the function:
dim xbm as p
xbm = require("hmac_hash")
path = "c:\path\to\DigitalHash\DLL\\"
? xbm.HMAC_HASH("my data", "my key", path)
= "Wnw05dPAEo44+bw1luJqAWksvhE="
? xbm.HMAC_HASH("my data", "my key", path, "HMACSHA1")
= "Wnw05dPAEo44+bw1luJqAWksvhE="
? xbm.HMAC_HASH("my data", "my key", path, "HMACSHA256")
= "kBhEzgLKNjSjjzQw7s240hvoY62kDG/wHDjYXry++nA="
? xbm.HMAC_HASH("my data", "my key", path, "HMACSHA384")
= "1819IdbuGcIweTIhYBwIK1mOmNrlpgRKK98gnDlVJyXug36wQoDWuBoGlB/GfMqc"
? xbm.HMAC_HASH("my data", "my key", path, "MACTripleDES")
ERROR: command: HMAC_HASH = hash.SignUsing(data,key,alg)
Exception has been thrown by the target of an invocation.
Specified key is not a valid size for this algorithm.
? xbm.HMAC_HASH("my data", "my key", path, "hMACmd5")
= "6YeAf6EEZBgdF4BqkAQe/w=="
? xbm.HMAC_HASH("my data", "my key", path, "garbage")
ERROR: command: HMAC_HASH = hash.SignUsing(data,key,alg)
Exception has been thrown by the target of an invocation.
Object reference not set to an instance of an object.A modified version of the hmac_hash() function and the required .NET DLL are shipped with Alpha Anywhere.
Plain SHA-1 Hash
Calculating a plain SHA-1 hash is a simpler problem. The following script will accomplish the purpose.
dim data as b dim result as b data = "HMACSHA256" dim sham as ::System::Security::Cryptography::SHA1Managed = new ::System::Security::Cryptography::SHA1Managed() result = sham.ComputeHash(data) showvar(*to_hex(result))
This gives:
57568b047095c4679873f2ad36d9a76fe92fbc0c
See Also