Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 德尔菲公司;CryptoAPI-如何计算HMAC-SHA512哈希?_Delphi_Hash_Delphi 2010_Hmac_Cryptoapi - Fatal编程技术网

Delphi 德尔菲公司;CryptoAPI-如何计算HMAC-SHA512哈希?

Delphi 德尔菲公司;CryptoAPI-如何计算HMAC-SHA512哈希?,delphi,hash,delphi-2010,hmac,cryptoapi,Delphi,Hash,Delphi 2010,Hmac,Cryptoapi,有人知道如何使用MS CryptoAPI在Delphi 2010+中计算HMAC-SHA512哈希吗 来自MS网站的示例生成了不正确的结果 我发现这个答案在某种程度上是有用的(因为它是从手动重写的),但它不是在Pascal中,我试图将它重构为Pascal是没有运气的。它可以工作,但仍然计算错误的结果 有人能帮我吗 编辑::这是我遇到问题的代码: uses Windows, JwaWinCrypt, JwaWinError; const BLOCK_SIZE = 64; typ

有人知道如何使用MS CryptoAPI在Delphi 2010+中计算HMAC-SHA512哈希吗

来自MS网站的示例生成了不正确的结果

我发现这个答案在某种程度上是有用的(因为它是从手动重写的),但它不是在Pascal中,我试图将它重构为Pascal是没有运气的。它可以工作,但仍然计算错误的结果

有人能帮我吗

编辑::这是我遇到问题的代码:

uses
  Windows,
  JwaWinCrypt,
  JwaWinError;

const
  BLOCK_SIZE = 64;

type
  EHMACError = class(Exception);

function WinError(const RetVal: BOOL; const FuncName: String): BOOL;
var
  dwResult: Integer;
begin
  Result:=RetVal;
  if not RetVal then begin
    dwResult:=GetLastError();
    raise EHMACError.CreateFmt('Error [x%x]: %s failed.'#13#10'%s', [dwResult, FuncName, SysErrorMessage(dwResult)]);
  end;
end;

function TBytesToHex(const Value: TBytes): String;
const
  dictionary: Array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
var
  i: Integer;
begin
  Result:='';
  for i:=0 to High(Value) do
    Result:=Result + dictionary[Value[i] shr 4] + dictionary[Value[i] and $0F];
end;

function hmac(AKey, AMessage: TBytes; Algid: ALG_ID): TBytes;

  function hash(const hProv: HCRYPTPROV; hData: TBytes): TBytes;
  var
    len, cb: DWORD;
    hHash: HCRYPTHASH;
  begin
    SetLength(Result, 0);
    WinError(CryptCreateHash(hProv, Algid, 0, 0, hHash), 'CryptCreateHash');
    try
      len:=Length(hData);
      cb:=SizeOf(len);
      WinError(CryptHashData(hHash, @hData[0], len, 0), 'CryptHashData');
      WinError(CryptGetHashParam(hHash, HP_HASHSIZE, @len, cb, 0), 'CryptGetHashParam(HP_HASHSIZE)');
      SetLength(Result, len);
      WinError(CryptGetHashParam(hHash, HP_HASHVAL, @Result[0], len, 0), 'CryptGetHashParam(HP_HASHVAL)');
    finally
      WinError(CryptDestroyHash(hHash), 'CryptDestroyHash');
    end;
  end;

  function double_hash(const hProv: HCRYPTPROV; hData1, hData2: TBytes): TBytes;
  var
    len, len1, len2, cb: DWORD;
    hHash: HCRYPTHASH;
  begin
    SetLength(Result, 0);
    WinError(CryptCreateHash(hProv, Algid, 0, 0, hHash), 'DH_CryptCreateHash');
    try
      len1:=Length(hData1);
      len2:=Length(hData2);
      cb:=SizeOf(DWORD);
      WinError(CryptHashData(hHash, @hData1[0], len1, 0), 'DH_CryptHashData(hData1)');
      WinError(CryptHashData(hHash, @hData2[0], len2, 0), 'DH_CryptHashData(hData1)');
      WinError(CryptGetHashParam(hHash, HP_HASHSIZE, @len, cb, 0), 'DH_CryptGetHashParam(HP_HASHSIZE)');
      SetLength(Result, len);
      WinError(CryptGetHashParam(hHash, HP_HASHVAL, @Result[0], len, 0), 'DH_CryptGetHashParam(HP_HASHVAL)');
    finally
      WinError(CryptDestroyHash(hHash), 'DH_CryptDestroyHash');
    end;
  end;

var
  hProv: HCRYPTPROV;
  hHash: HCRYPTHASH;
  i_key_pad, o_key_pad: TBytes;
  data, ret: TBytes;
  len, i: Integer;
  c: Byte;
  ifree: Boolean;
begin
  ifree:=False;
  SetLength(Result, 0);
  SetLength(i_key_pad, BLOCK_SIZE);
  SetLength(o_key_pad, BLOCK_SIZE);
  WinError(CryptAcquireContext(hProv, Nil, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT), 'CryptAcquireContext');
  try
    data:=AKey;
    len:=Length(data);
    if len > BLOCK_SIZE then begin
      data:=hash(hProv, data);
      ifree:=True;
    end;
    //
    i:=BLOCK_SIZE-1;
    while i >= 0 do begin
      if i < len then
        c:=data[i]
      else
        c:=0;
      i_key_pad[i]:=$36 xor c;
      o_key_pad[i]:=$5c xor c;
      Dec(i);
    end;
    data:=double_hash(hProv, i_key_pad, AMessage);
    Result:=double_hash(hProv, o_key_pad, data);
    SetLength(data, 0);
  finally
    if ifree then
      SetLength(data, 0);
    SetLength(i_key_pad, 0);
    SetLength(o_key_pad, 0);
    WinError(CryptReleaseContext(hProv, 0), 'CryptReleaseContext');
  end;
end;
例如:

tbytestochex(hmac('pass','test',CALG_SHA_512))生成(十六进制编码)

1319BB7BAEFC3FBAF07824261C240CECD04A54CD83CDF0DEB68E56CADF20E7C644E2E956660AB9DF47A1950217390DF5EC3D0B9236D59917AFC4F3607CF980

鉴于产生

46BECA277A5FEC10BEBA65B0C2FB3917115F352EB8B2560E9ADA0A3DBAFB6C7A3FC456B113A07C4A9C856B633B70B2403907CA89402772393E3F97E78684


对于相同的输入

我的问题的完整工作解决方案,感谢@whosrdaddy的帮助

//
// HMAC-SHA512 - cryptoapi hash generation
//
// based on:
//   https://en.wikipedia.org/wiki/HMAC
//   https://github.com/ogay/hmac
//
// refactored from:
//   https://stackoverflow.com/questions/41384395/wrong-result-for-base64-string-of-hmac-sha1-using-crypto-api/41387095#41387095
//
unit CryptoAPI_HMAC_SHA512;

interface

uses
  SysUtils,
  Classes;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: TBytes): TBytes; overload;
function CryptoAPI_Hash_HmacSHA512(const InString, Password: String): String; overload;

implementation

uses
  Windows,
  JwaWinCrypt,
  JwaWinError;

const
  BLOCK_SIZE  = 128; // bytes for SHA512

type
  EHMACError = class(Exception);

function WinError(const RetVal: BOOL; const FuncName: String): BOOL;
var
  dwResult: Integer;
begin
  Result:=RetVal;
  if not RetVal then begin
    dwResult:=GetLastError();
    raise EHMACError.CreateFmt('Error [x%x]: %s failed.'#13#10'%s', [dwResult, FuncName, SysErrorMessage(dwResult)]);
  end;
end;

function hmac(AKey, AMessage: TBytes; Algid: ALG_ID): TBytes;

  function hash(const hProv: HCRYPTPROV; hData1, hData2: TBytes): TBytes;
  var
    len, len1, len2, cb: DWORD;
    hHash: HCRYPTHASH;
  begin
    SetLength(Result, 0);
    WinError(CryptCreateHash(hProv, Algid, 0, 0, hHash), 'CryptCreateHash');
    try
      len:=0;
      len1:=Length(hData1);
      len2:=Length(hData2);
      cb:=SizeOf(DWORD);
      WinError(CryptHashData(hHash, @hData1[0], len1, 0), 'CryptHashData(hData1)');
      if len2 > 0 then
        WinError(CryptHashData(hHash, @hData2[0], len2, 0), 'CryptHashData(hData1)');
      WinError(CryptGetHashParam(hHash, HP_HASHSIZE, @len, cb, 0), 'CryptGetHashParam(HP_HASHSIZE)');
      SetLength(Result, len);
      WinError(CryptGetHashParam(hHash, HP_HASHVAL, @Result[0], len, 0), 'CryptGetHashParam(HP_HASHVAL)');
    finally
      WinError(CryptDestroyHash(hHash), 'CryptDestroyHash');
    end;
  end;

var
  hProv: HCRYPTPROV;
  i_key_pad, o_key_pad: TBytes;
  data: TBytes;
  emptyArray: TBytes;
  len, i: Integer;
  c: Byte;
  ifree: Boolean;
begin
  ifree:=False;
  SetLength(Result, 0);
  SetLength(emptyArray, 0);
  SetLength(i_key_pad, BLOCK_SIZE);
  SetLength(o_key_pad, BLOCK_SIZE);
  WinError(CryptAcquireContext(hProv, Nil, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT), 'CryptAcquireContext');
  try
    data:=AKey;
    len:=Length(data);
    if len > BLOCK_SIZE then begin
      data:=hash(hProv, data, emptyArray);
      len:=Length(data);
      ifree:=True;
    end;
    //
    i:=BLOCK_SIZE-1;
    while i >= 0 do begin
      c:=0;
      if i < len then
        c:=data[i];
      i_key_pad[i]:=$36 xor c;
      o_key_pad[i]:=$5c xor c;
      Dec(i);
    end;
    if ifree then
      SetLength(data, 0);
    data:=hash(hProv, i_key_pad, AMessage);
    Result:=hash(hProv, o_key_pad, data);
    SetLength(data, 0);
  finally
    SetLength(i_key_pad, 0);
    SetLength(o_key_pad, 0);
    WinError(CryptReleaseContext(hProv, 0), 'CryptReleaseContext');
  end;
end;

function TBytesToHex(const Value: TBytes): String;
const
  dictionary: Array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
var
  i: Integer;
begin
  Result:='';
  for i:=0 to High(Value) do
    Result:=Result + dictionary[Value[i] shr 4] + dictionary[Value[i] and $0F];
end;

// source: https://stackoverflow.com/a/26892830/2111514
function MBCSString(const s: UnicodeString; CodePage: Word): RawByteString;
var
  enc: TEncoding;
  bytes: TBytes;
begin
  enc:=TEncoding.GetEncoding(CodePage);
  try
    bytes:=enc.GetBytes(s);
    SetLength(Result, Length(bytes));
    Move(Pointer(bytes)^, Pointer(Result)^, Length(bytes));
    SetCodePage(Result, CodePage, False);
  finally
    enc.Free;
  end;
end;

function UnicodeStringToTBytes(const Value: String): TBytes;
var
  ansi: AnsiString;
begin
  ansi:=MBCSString(Value, 65001); // Unicode (UTF-8) codepage
  Result:=BytesOf(ansi);
  ansi:='';
end;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: TBytes): TBytes;
begin
  SetLength(Result, 0);
  if Length(Password) = 0 then
    raise EHMACError.Create('Error: Password length must be greater then 0!');

  Result:=hmac(Password, InString, CALG_SHA_512);
end;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: String): String;
var
  input_bytes, input_password: TBytes;
begin
  input_bytes:=UnicodeStringToTBytes(InString);
  input_password:=UnicodeStringToTBytes(Password);
  try
    Result:=TBytesToHex(CryptoAPI_Hash_HmacSHA512(input_bytes, input_password));
  finally
    SetLength(input_password, 0);
    SetLength(input_bytes, 0);
  end;
end;

end.
//
//HMAC-SHA512-加密API哈希生成
//
//基于:
//   https://en.wikipedia.org/wiki/HMAC
//   https://github.com/ogay/hmac
//
//重构自:
//   https://stackoverflow.com/questions/41384395/wrong-result-for-base64-string-of-hmac-sha1-using-crypto-api/41387095#41387095
//
单位CryptoAPI_HMAC_SHA512;
接口
使用
SysUtils,
班级;
函数CryptoAPI_Hash_HmacSHA512(常量指令,密码:TBytes):TBytes;超载;
函数CryptoAPI_Hash_HmacSHA512(常量指令,密码:字符串):字符串;超载;
实施
使用
窗户,
JwaWinCrypt,
JwaWinError;
常数
块大小=128;//SHA512的字节数
类型
EHMAError=类(异常);
函数WinError(const RetVal:BOOL;const FuncName:String):BOOL;
变量
dwResult:整数;
开始
结果:=RetVal;
如果没有返回,则开始
dwResult:=GetLastError();
raise EHMAError.CreateFmt('Error[x%x]:%s失败。“#13#10'%s',[dwResult,FuncName,SysErrorMessage(dwResult)];
结束;
结束;
函数hmac(AKey,AMessage:TBytes;Algid:ALG_ID):TBytes;
函数散列(const hProv:HCRYPTPROV;hData1、hData2:TBytes):TBytes;
变量
蓝,蓝1,蓝2,cb:DWORD;
hHash:HCRYPTHASH;
开始
SetLength(结果为0);
WinError(CryptCreateHash(hProv,Algid,0,0,hHash),“CryptCreateHash”);
尝试
len:=0;
len1:=长度(hData1);
len2:=长度(hData2);
cb:=SizeOf(DWORD);
WinError(CryptHashData(hHash,@hData1[0],len1,0),“CryptHashData(hData1)”;
如果len2>0,则
WinError(CryptHashData(hHash,@hData2[0],len2,0),“CryptHashData(hData1)”;
WinError(CryptGetHashParam(hHash,HP_HASHSIZE,@len,cb,0),“CryptGetHashParam(HP_HASHSIZE)”;
设置长度(结果,len);
WinError(CryptGetHashParam(hHash,HP_HASHVAL,@Result[0],len,0),“CryptGetHashParam(HP_HASHVAL)”;
最后
WinError(CryptDestroyHash(hHash),“CryptDestroyHash”);
结束;
结束;
变量
hProv:HCRYPTPROV;
i_键盘,o_键盘:t字节;
数据:t字节;
空数组:t字节;
len,i:整数;
c:字节;
ifree:布尔型;
开始
ifree:=假;
SetLength(结果为0);
设置长度(空数组,0);
设置长度(键盘、块大小);
设置长度(键盘、块大小);
WinError(CryptAcquireContext(hProv,Nil,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,CRYPT_VERIFYCONTEXT),“CryptAcquireContext”);
尝试
数据:=AKey;
len:=长度(数据);
如果len>块大小,则开始
数据:=散列(hProv、数据、空数组);
len:=长度(数据);
ifree:=真;
结束;
//
i:=块_尺寸-1;
当i>=0开始时
c:=0;
如果我是莱恩的话
c:=数据[i];
i_key_pad[i]:=$36或c;
o_key_pad[i]:=$5c或xoc;
十二月一日;
结束;
如果我是自由的话
设置长度(数据,0);
数据:=散列(hProv、键盘、消息);
结果:=散列(hProv、o_键盘、数据);
设置长度(数据,0);
最后
设置长度(i_键盘,0);
设置长度(o_键盘,0);
WinError(CryptReleaseContext(hProv,0),'CryptReleaseContext');
结束;
结束;
函数tbytestochex(常量值:TBytes):字符串;
常数
字典:Char=('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f')的数组[0..15];
变量
i:整数;
开始
结果:='';
对于i:=0到高(值)do
结果:=结果+字典[Value[i]shr 4]+字典[Value[i]和$0F];
结束;
//资料来源:https://stackoverflow.com/a/26892830/2111514
函数MBCSString(const s:UnicodeString;CodePage:Word):RawByteString;
变量
enc:TEncoding;
字节:TBytes;
开始
enc:=TEncoding.GetEncoding(代码页);
尝试
字节:=enc.GetBytes(s);
SetLength(结果,长度(字节));
移动(指针(字节)^,指针(结果)^,长度(字节));
SetCodePage(结果、代码页、错误);
最后
免费附件;
结束;
结束;
函数UnicodestingToBytes(常量值:字符串):TBytes;
变量
ansi:AnsiString;
开始
ansi:=MBCSString(值65001);//Unicode(UTF-8)代码页
结果:=字节数(ansi);
ansi:='';
结束;
函数CryptoAPI_Hash_HmacSHA512(常量指令,密码:TBytes):TBytes;
开始
SetLength(结果为0);
如果长度(密码)=0,则
raise EHMASERROR.Create('错误:密码长度必须大于0!');
结果:=hmac(密码、指示、计算值512);
结束;
函数CryptoAPI_Hash_HmacSHA512(常量指令,密码:字符串):字符串;
变量
输入字节,输入密码:t字节;
开始
输入字节:=Unicodesringtotbytes(InString);
输入_密码:=UnicodestingToBytes(密码);
尝试
结果:=TBytesToHex(CryptoAPI_哈希_HmacSHA512(输入字节,输入密码));
最后
设置长度(输入密码,0);
SetLength(输入_字节,0);
结束;
结束;
结束。

我非常怀疑ms示例是否产生了错误的结果。您是否偶然使用字符串进行散列计算?不,所有内容都转换为ANSI,然后再转换为TBytes,与使用在线生成器测试时相比,结果有所不同。我肯定正在散列的数据
//
// HMAC-SHA512 - cryptoapi hash generation
//
// based on:
//   https://en.wikipedia.org/wiki/HMAC
//   https://github.com/ogay/hmac
//
// refactored from:
//   https://stackoverflow.com/questions/41384395/wrong-result-for-base64-string-of-hmac-sha1-using-crypto-api/41387095#41387095
//
unit CryptoAPI_HMAC_SHA512;

interface

uses
  SysUtils,
  Classes;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: TBytes): TBytes; overload;
function CryptoAPI_Hash_HmacSHA512(const InString, Password: String): String; overload;

implementation

uses
  Windows,
  JwaWinCrypt,
  JwaWinError;

const
  BLOCK_SIZE  = 128; // bytes for SHA512

type
  EHMACError = class(Exception);

function WinError(const RetVal: BOOL; const FuncName: String): BOOL;
var
  dwResult: Integer;
begin
  Result:=RetVal;
  if not RetVal then begin
    dwResult:=GetLastError();
    raise EHMACError.CreateFmt('Error [x%x]: %s failed.'#13#10'%s', [dwResult, FuncName, SysErrorMessage(dwResult)]);
  end;
end;

function hmac(AKey, AMessage: TBytes; Algid: ALG_ID): TBytes;

  function hash(const hProv: HCRYPTPROV; hData1, hData2: TBytes): TBytes;
  var
    len, len1, len2, cb: DWORD;
    hHash: HCRYPTHASH;
  begin
    SetLength(Result, 0);
    WinError(CryptCreateHash(hProv, Algid, 0, 0, hHash), 'CryptCreateHash');
    try
      len:=0;
      len1:=Length(hData1);
      len2:=Length(hData2);
      cb:=SizeOf(DWORD);
      WinError(CryptHashData(hHash, @hData1[0], len1, 0), 'CryptHashData(hData1)');
      if len2 > 0 then
        WinError(CryptHashData(hHash, @hData2[0], len2, 0), 'CryptHashData(hData1)');
      WinError(CryptGetHashParam(hHash, HP_HASHSIZE, @len, cb, 0), 'CryptGetHashParam(HP_HASHSIZE)');
      SetLength(Result, len);
      WinError(CryptGetHashParam(hHash, HP_HASHVAL, @Result[0], len, 0), 'CryptGetHashParam(HP_HASHVAL)');
    finally
      WinError(CryptDestroyHash(hHash), 'CryptDestroyHash');
    end;
  end;

var
  hProv: HCRYPTPROV;
  i_key_pad, o_key_pad: TBytes;
  data: TBytes;
  emptyArray: TBytes;
  len, i: Integer;
  c: Byte;
  ifree: Boolean;
begin
  ifree:=False;
  SetLength(Result, 0);
  SetLength(emptyArray, 0);
  SetLength(i_key_pad, BLOCK_SIZE);
  SetLength(o_key_pad, BLOCK_SIZE);
  WinError(CryptAcquireContext(hProv, Nil, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT), 'CryptAcquireContext');
  try
    data:=AKey;
    len:=Length(data);
    if len > BLOCK_SIZE then begin
      data:=hash(hProv, data, emptyArray);
      len:=Length(data);
      ifree:=True;
    end;
    //
    i:=BLOCK_SIZE-1;
    while i >= 0 do begin
      c:=0;
      if i < len then
        c:=data[i];
      i_key_pad[i]:=$36 xor c;
      o_key_pad[i]:=$5c xor c;
      Dec(i);
    end;
    if ifree then
      SetLength(data, 0);
    data:=hash(hProv, i_key_pad, AMessage);
    Result:=hash(hProv, o_key_pad, data);
    SetLength(data, 0);
  finally
    SetLength(i_key_pad, 0);
    SetLength(o_key_pad, 0);
    WinError(CryptReleaseContext(hProv, 0), 'CryptReleaseContext');
  end;
end;

function TBytesToHex(const Value: TBytes): String;
const
  dictionary: Array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
var
  i: Integer;
begin
  Result:='';
  for i:=0 to High(Value) do
    Result:=Result + dictionary[Value[i] shr 4] + dictionary[Value[i] and $0F];
end;

// source: https://stackoverflow.com/a/26892830/2111514
function MBCSString(const s: UnicodeString; CodePage: Word): RawByteString;
var
  enc: TEncoding;
  bytes: TBytes;
begin
  enc:=TEncoding.GetEncoding(CodePage);
  try
    bytes:=enc.GetBytes(s);
    SetLength(Result, Length(bytes));
    Move(Pointer(bytes)^, Pointer(Result)^, Length(bytes));
    SetCodePage(Result, CodePage, False);
  finally
    enc.Free;
  end;
end;

function UnicodeStringToTBytes(const Value: String): TBytes;
var
  ansi: AnsiString;
begin
  ansi:=MBCSString(Value, 65001); // Unicode (UTF-8) codepage
  Result:=BytesOf(ansi);
  ansi:='';
end;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: TBytes): TBytes;
begin
  SetLength(Result, 0);
  if Length(Password) = 0 then
    raise EHMACError.Create('Error: Password length must be greater then 0!');

  Result:=hmac(Password, InString, CALG_SHA_512);
end;

function CryptoAPI_Hash_HmacSHA512(const InString, Password: String): String;
var
  input_bytes, input_password: TBytes;
begin
  input_bytes:=UnicodeStringToTBytes(InString);
  input_password:=UnicodeStringToTBytes(Password);
  try
    Result:=TBytesToHex(CryptoAPI_Hash_HmacSHA512(input_bytes, input_password));
  finally
    SetLength(input_password, 0);
    SetLength(input_bytes, 0);
  end;
end;

end.