Delphi – 无法通过RFC 4231测试向量获得HMAC-SHA256
我需要像“
HMAC-SHA256 in Delphi”中的上一个问题一样访问Amazon REST服务.由于这必须在D2010中,我正在尝试使用最新的libeay32.dll来传递RFC 4231中的测试向量:
http://tools.ietf.org/html/rfc4231 有没有人有一个方法,使用这个库在Delphi中传递这些测试? shunty在我提到的帖子中发布的代码传递了前两个测试向量以及第五个,但它在第三和第四个失败.这些向量超过64个字节,因为我需要为Amazon签名的所有url超过64个字节,这是一个问题.我无法弄清楚我做错了什么. OpenSSL测试在hmactest.c中,但它只检查EVP_md5,并且测试向量与RFC中的测试向量不完全相同.我需要这个使用SHA256,所以我可以验证RFC中的测试向量.我正在使用以下常量进行测试(现在为将来的查看者更新常量以修复下面评论中提到的复制和粘贴错误): const LIBEAY_DLL_NAME = 'libeay32.dll'; EVP_MAX_MD_SIZE = 64; //RFC 4231 Test case 1 TEST1_KEY: string = '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'; TEST1_DATA: string = '4869205468657265'; TEST1_DIGEST: string = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; //RFC 4231 Test case 2 TEST2_KEY = '4a656665'; TEST2_DATA = '7768617420646f2079612077616e7420666f72206e6f7468696e673f'; TEST2_DIGEST = '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843'; //RFC 4231 Test case 3 TEST3_KEY = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; TEST3_DATA = 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'; TEST3_DIGEST = '773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe'; //RFC 4231 Test case 4 TEST4_KEY = '0102030405060708090a0b0c0d0e0f10111213141516171819'; TEST4_DATA = 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'; TEST4_DIGEST = '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b'; //RFC 4231 Test case 5 TEST5_KEY = '0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'; TEST5_DATA = '546573742057697468205472756e636174696f6e'; TEST5_DIGEST = 'a3b6167473100ee06e0c796c2955552b'; 我不知道这个代码是如何通过shunty粘贴的,因为它在这里看起来很糟糕(我是一个stackoverflow新手).我像他一样使用RAND_seed而不是RAND_load_file,但是否则它是相同的: function TForm1.GetHMAC(const AKey,AData: string): TBytes; var key,data: TBytes; md_len: integer; res: PByte; buf: PInteger; rand_val: Integer; begin OpenSSL_add_all_algorithms; Randomize; rand_val := Random(100); GetMem(buf,rand_val); try RAND_seed(buf,rand_val); 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 SetLength(Result,md_len); finally FreeMem(buf); end; end; 我用来测试的代码看起来像这样.这种特殊方法适用于失败的测试3.结果是bb861233f283aef2ef7aea09785245c9f3c62720c9d04e0c232789f27a586e44,但它应该等于TEST3_DIGEST的常量十六进制值: procedure TForm1.btnTestCase3Click(Sender: TObject); var LBytesDigest: TBytes; LHashString: string; LHexDigest: string; begin LBytesDigest := GetHMAC(HexToStr(TEST3_KEY),HexToStr(TEST3_DATA)); LHexDigest := LowerCase(BytesToHex(LBytesDigest)); if LHexDigest = TEST3_DIGEST then begin Memo1.Lines.Add('SUCCESS: Matches test case'); Memo1.Lines.Add(LHexDigest); end else begin Memo1.Lines.Add('ERROR: Does not match test case'); Memo1.Lines.Add('Result: ' + LHexDigest); Memo1.Lines.Add('Test Case: ' + TEST3_DIGEST); end; end; 有任何想法吗?我即将放弃,只是使用他们提供的库创建一个.NET应用程序… 解决方法
您正在使用D2009(通过使用TEncoding可以明显看出),这意味着您正在处理UnicodeString,但是您没有在您的逻辑中考虑Unicode. RFC不对字符进行操作,它对字节进行操作.您的测试数据包含十六进制编码字符串.当您将它们解码为(Unicode)字符串值时,许多结果字符超出了ASCII字符范围,这意味着它们必须由Ansi代码页解释,然后才能正确地将它们转换为UTF-8(您不应该这样做)无论如何都要在这种情况下使用).
您需要更改实现以将十六进制字符串直接解码为TBytes(您可以使用Classes.HexToBin()),以便保留正确的字节值并传递给HMAC,并摆脱TEncoding.UTF8.GetBytes()彻底: function TForm1.GetHMAC(const AKey,AData: TBytes): TBytes; var md_len: integer; res: PByte; buf: PInteger; rand_val: Integer; begin OpenSSL_add_all_algorithms; Randomize; rand_val := Random(100); GetMem(buf,rand_val); try RAND_seed(buf,rand_val); md_len := EVP_MAX_MD_SIZE; SetLength(Result,md_len); res := HMAC(EVP_sha256,Pointer(AKey),Length(AKey),Pointer(AData),Length(AData),@Result[0],md_len); if (res <> nil) then SetLength(Result,md_len); finally FreeMem(buf); end; end; function HexToBytes(const S: String): TBytes; begin SetLength(Result,Length(S) div 2); SetLength(Result,HexToBin(PChar(S),Pointer(Result),Length(Result))); en; procedure TForm1.btnTestCase3Click(Sender: TObject); var LBytesDigest: TBytes; LHashString: string; LHexDigest: string; begin LBytesDigest := GetHMAC(HexToBytes(TEST3_KEY),HexToBytes(TEST3_DATA)); LHexDigest := LowerCase(BytesToHex(LBytesDigest)); if LHexDigest = TEST3_DIGEST then begin Memo1.Lines.Add('SUCCESS: Matches test case'); Memo1.Lines.Add(LHexDigest); end else begin Memo1.Lines.Add('ERROR: Does not match test case'); Memo1.Lines.Add('Result: ' + LHexDigest); Memo1.Lines.Add('Test Case: ' + TEST3_DIGEST); end; end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |