HMAC-SHA256 in Delphi

2019-01-25 13:09发布

问题:

I need to generate HMAC-SHA256 signatures for the Amazon web services API. The old DCPcrypt library has sha256 routines but does not do HMAC signing. Anyone know of a free hashing library I could use?

回答1:

After a little more searching I found OpenStreamSec - which looks like it was abandoned a few years ago but still compiles in D2007.

http://sourceforge.net/projects/openstrsecii/

Generating a HMAC-256 for Amazon is really simple:

StrToMime64(HMACString(haSHA256, SecretKey, 32, DataToHash));


回答2:

My favourite answer - I would use the OpenSSL libraries, the HMAC function. I've successfully used the OpenSSL libraries in Delphi by adopting and adapting work from M Ferrante http://www.disi.unige.it/person/FerranteM/delphiopenssl/
For other OpenSSL signing etc see this link
In D2010 it's something like this (libeay32 is the unit taken from the web site and slightly modified for unicode/D2010):

uses libeay32;

const
  LIBEAY_DLL_NAME = 'libeay32.dll';
  EVP_MAX_MD_SIZE = 64;

function EVP_sha256: pEVP_MD; cdecl; external LIBEAY_DLL_NAME;
function HMAC(evp: pEVP_MD; key: PByte; key_len: integer; 
              data: PByte; data_len: integer; 
              md: PByte; var md_len: integer): PByte; cdecl; external LIBEAY_DLL_NAME;

function GetHMAC(const AKey, AData: string): TBytes;
var
  key, data: TBytes;
  md_len: integer;
  res: PByte;
begin
  OpenSSL_add_all_algorithms;
  // Seed the pseudo-random number generator
  // This should be something a little more "random"!
  RAND_load_file('c:\windows\paint.exe', 512);

  key := TEncoding.UTF8.GetBytes(AKey);
  data := TEncoding.UTF8.GetBytes(AData);
  md_len := EVP_MAX_MD_SIZE;
  SetLength(result, md_len);
  res := HMAC(EVP_sha256, @key[0], Length(key), @data[0], Length(data), @result[0], md_len);
  if (res <> nil) then
  begin
    SetLength(result, md_len);
  end;
end;

Then call it with a key phrase and data string. The result is a TBytes which can be converted as required eg to Base64 using something like JclMime or a simple HexToString type function.
For older version of Delphi you'll have to do a bit of changing of PBytes to PChars or something similar.
Disclaimer: I've got no reference data to test this on but it seems to work ok!



回答3:

Delphi ships with Indy installed, and Indy has a TIdHMACSHA256 class:

uses
  IdGlobal, IdHashSHA, IdHMAC, IdHMACSHA1, IdSSLOpenSSL;

function CalculateHMACSHA256(const value, salt: String): String;
var
  hmac: TIdHMACSHA256;
  hash: TIdBytes;
begin
  LoadOpenSSLLibrary;
  if not TIdHashSHA256.IsAvailable then
    raise Exception.Create('SHA256 hashing is not available!');
  hmac := TIdHMACSHA256.Create;
  try
    hmac.Key := IndyTextEncoding_UTF8.GetBytes(salt);
    hash := hmac.HashValue(IndyTextEncoding_UTF8.GetBytes(value));
    Result := ToHex(hash);
  finally
    hmac.Free;
  end;
end;


回答4:

Have you looked at the answers to this SO question?



回答5:

HMAC is just a function that uses SHA256 to calculate a hash according to some defined rules. If you look at Wikipedia it has a pseudocode example.

You could also call into .NET's HMAC Class in System.Security.Cryptography via COM interrop.



回答6:

Regarding the answer from Jacob: OpenStrSecII is a branch of StreamSec Tools 2.1, which is sold under a commercial no-nonsense license and today (Feb 8, 2012) has support for Delphi Win32 up to and including Delphi XE2. StreamSec Tools 4.0 has support for Win64 as well.