我使用加密API使用下面的代码,而且我没有得到基于其他API和库测试的结果。
我正在使用密钥," 密钥"数据是" 消息"
例如,使用Indy的TidHMACSHA1,我得到2088df74d5f2146b48146caf4965377e9d0be3a4
我使用在线生成器(例如http://www.freeformatter.com/hmac-generator.html)得到相同的结果。
用我编写的代码(见下文),我得到4a52c3c0abc0a06049d1ab648bb4057e3ff5f359
代码如下,我使用的是JEDI wcrypt2.pas标题
function Hashhmacsha1(const Key, Value: AnsiString): AnsiString;
var
hCryptProvider: HCRYPTPROV;
hHash: HCRYPTHASH;
hKey: HCRYPTKEY;
bHash: array[0..$7F] of Byte;
dwHashLen: dWord;
i: Integer;
hHmacHash: HCRYPTHASH;
bHmacHash: array[0..$7F] of Byte;
dwHmacHashLen: dWord;
hmac_info : Wcrypt2.HMAC_INFO;
begin
dwHashLen := 32;
dwHmacHashLen := 32;
{get context for crypt default provider}
if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
begin
{create hash-object }
if CryptCreateHash(hCryptProvider, CALG_SHA1, 0, 0, @hHash) then
begin
{get hash from password}
if CryptHashData(hHash, @Key[1], Length(Key), 0) then
begin
// hHash is now a hash of the provided key, (SHA1)
// Now we derive a key for it
if CryptDeriveKey(hCryptProvider, CALG_RC4, hHash, 0, @hKey) then
begin
//hkey now holds our key. So we have do the whole thing over again
//ZeroMemory( hmac_info, SizeOf(hmac_info) );
hmac_info.HashAlgid := CALG_SHA1;
if CryptCreateHash(hCryptProvider, CALG_HMAC, hKey, 0, @hHmacHash) then
begin
{get hash from password}
if CryptSetHashParam( hHmacHash, HP_HMAC_INFO, @hmac_info, 0) then
begin
if CryptHashData(hHmacHash, @Value[1], Length(Value), 0) then
begin
if CryptGetHashParam(hHmacHash, HP_HASHVAL, @bHmacHash[0], @dwHmacHashLen, 0) then
begin
for i := 0 to dwHmacHashLen-1 do
Result := Result + IntToHex(bHmacHash[i], 2);
end
else
WriteLn( 'CryptGetHashParam ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptHashData ERROR --> ' + SysErrorMessage(GetLastError)) ;
{destroy hash-object}
CryptDestroyHash(hHmacHash);
CryptDestroyKey(hKey);
end
else
WriteLn( 'CryptSetHashParam ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptCreateHash ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptDeriveKey ERROR --> ' + SysErrorMessage(GetLastError)) ;
end;
{destroy hash-object}
CryptDestroyHash(hHash);
end;
{release the context for crypt default provider}
CryptReleaseContext(hCryptProvider, 0);
end;
Result := AnsiLowerCase(Result);
end;
我显然做错了什么,但我不知道是什么?
答案 0 :(得分:2)
所以我找到了一个解决方案,在为数据"消息"生成HMAC_SHA1时用键"键"生成预期的哈希2088df74d5f2146b48146caf4965377e9d0be3a4
如您所见,此代码使用CryptImportKey
代替CryptDeriveKey
,这似乎可以解决问题。似乎使用CryptDeriveKey实际上是使用数据"消息"生成HMAC_SHA1哈希。和密钥"密钥"的SHA1哈希最初认为编码为RC4而不是明文密钥。
该代码适用于长度最多16个字符的密钥,任何更大的密码,仅使用前16个字符。我发布了第二个问题来询问这个问题!!
代码发布在下面。
function Hashhmacsha1(const Key, Value: AnsiString): AnsiString;
const
KEY_LEN_MAX = 16;
var
hCryptProvider: HCRYPTPROV;
hHash: HCRYPTHASH;
hKey: HCRYPTKEY;
bHash: array[0..$7F] of Byte;
dwHashLen: dWord;
i: Integer;
hPubKey : HCRYPTKey;
hHmacHash: HCRYPTHASH;
bHmacHash: array[0..$7F] of Byte;
dwHmacHashLen: dWord;
hmac_info : Wcrypt2.HMAC_INFO;
keyBlob: record
keyHeader: BLOBHEADER;
keySize: DWORD;
keyData: array[0..KEY_LEN_MAX-1] of Byte;
end;
keyLen : INTEGER;
begin
dwHashLen := 32;
dwHmacHashLen := 32;
{get context for crypt default provider}
if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) then
begin
{create hash-object MD5}
if CryptCreateHash(hCryptProvider, CALG_SHA1, 0, 0, @hHash) then
begin
{get hash from password}
if CryptHashData(hHash, PByte(Key), Length(Key), 0) then
begin
// hHash is now a hash of the provided key, (SHA1)
// Now we derive a key for it
hPubKey := 0;
FillChar(keyBlob, SizeOf(keyBlob), 0);
keyBlob.keyHeader.bType := PLAINTEXTKEYBLOB;
keyBlob.keyHeader.bVersion := CUR_BLOB_VERSION;
keyBlob.keyHeader.aiKeyAlg := CALG_RC4;
KeyBlob.keySize := KEY_LEN_MAX;
if(Length(key) < (KEY_LEN_MAX))then
KeyLen := Length(key)
else
KeyLen := KEY_LEN_MAX;
Move(Key[1], KeyBlob.keyData[0], KeyLen );
if CryptImportKey(hCryptProvider, @keyBlob, SizeOf(KeyBlob), hPubKey, 0, @hKey) then
begin
//hkey now holds our key. So we have do the whole thing over again
ZeroMemory( @hmac_info, SizeOf(hmac_info) );
hmac_info.HashAlgid := CALG_SHA1;
if CryptCreateHash(hCryptProvider, CALG_HMAC, hKey, 0, @hHmacHash) then
begin
if CryptSetHashParam( hHmacHash, HP_HMAC_INFO, @hmac_info, 0) then
begin
if CryptHashData(hHmacHash, @Value[1], Length(Value), 0) then
begin
if CryptGetHashParam(hHmacHash, HP_HASHVAL, @bHmacHash[0], @dwHmacHashLen, 0) then
begin
for i := 0 to dwHmacHashLen-1 do
Result := Result + IntToHex(bHmacHash[i], 2);
end
else
WriteLn( 'CryptGetHashParam ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptHashData ERROR --> ' + SysErrorMessage(GetLastError)) ;
{destroy hash-object}
CryptDestroyHash(hHmacHash);
CryptDestroyKey(hKey);
end
else
WriteLn( 'CryptSetHashParam ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptCreateHash ERROR --> ' + SysErrorMessage(GetLastError)) ;
end
else
WriteLn( 'CryptDeriveKey ERROR --> ' + SysErrorMessage(GetLastError)) ;
end;
{destroy hash-object}
CryptDestroyHash(hHash);
end;
{release the context for crypt default provider}
CryptReleaseContext(hCryptProvider, 0);
end;
Result := AnsiLowerCase(Result);
end;
答案 1 :(得分:1)
通过使用OpenSLL,我能够获得超过16个字节的密钥的正确结果。而不是大约10个Win32 Crypt调用,它完成了三个:init,HMAC和cleanup。
答案 2 :(得分:0)
我不使用你的功能,所以如果我错了就纠正我:我没有看到你在哪里计算HMACSHA1(&#39; message&#39;,&#39; key&#39;)。
在CryptCreateHash(hCryptProvider, CALG_HMAC, hKey, 0, @hHmacHash)
之后我猜你正在计算HMACSHA1(&#39; message&#39;,hkey),其中派生密钥hkey以某种方式用RC4计算。