2012-04-03 28 views
5

Tôi cần truy cập các dịch vụ của Amazon REST như câu hỏi trước tại "HMAC-SHA256 in Delphi". Vì đây có được trong D2010 Tôi đang cố gắng sử dụng libeay32.dll mới nhất để vượt qua các vectơ thử nghiệm trong RFC 4231:Delphi - Không thể nhận HMAC-SHA256 để vượt qua các vectơ kiểm tra RFC 4231

http://tools.ietf.org/html/rfc4231

Có ai có một phương pháp mà qua những thử nghiệm trong Delphi sử dụng thư viện này ? Các mã được đăng bởi shunty trong bài tôi gọi đi qua hai vector thử nghiệm đầu tiên cũng như các thứ năm, nhưng nó không thành công trong thứ ba và thứ tư. Những vectơ đó là trên 64 byte và vì tất cả các url mà tôi cần ký cho Amazon là hơn 64 byte, đây là một vấn đề. Tôi đã không thể tìm ra nếu tôi đang làm điều gì đó sai trái. Kiểm tra OpenSSL là hmactest.c, nhưng nó chỉ kiểm tra EVP_md5 và các vectơ thử nghiệm không giống như trong RFC. Tôi cần điều này để làm việc với SHA256 vì vậy tôi có thể xác minh đối với các vectơ thử nghiệm trong RFC. Tôi đang sử dụng hằng số sau cho các bài kiểm tra (hằng số hiện nay được cập nhật cho khán giả trong tương lai để sửa chữa sao chép và dán tôi lỗi đề cập trong các ý kiến ​​dưới đây):

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'; 

Tôi không biết làm thế nào mã này bằng cách shunty sẽ xem xét dán vào bởi vì nó trông khủng khiếp ở đây (tôi là một người mới stackoverflow). Tôi đã sử dụng RAND_seed thay vì RAND_load_file như anh ấy đã làm, nhưng nếu không nó giống nhau:

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; 

Mã tôi sử dụng để kiểm tra trông như thế này. Phương pháp cụ thể này là cho thử nghiệm 3 mà không thành công. Kết quả là bb861233f283aef2ef7aea09785245c9f3c62720c9d04e0c232789f27a586e44, nhưng nó phải là tương đương với giá trị hex liên tục cho 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; 

Bất kỳ ý tưởng? Tôi sắp từ bỏ và chỉ cần tạo ứng dụng .NET bằng thư viện mà họ cung cấp ...

Trả lời

6

Bạn đang sử dụng D2009 + (hiển nhiên là bạn sử dụng TEncoding), nghĩa là bạn đang xử lý UnicodeString, nhưng bạn không dùng Unicode trong tài khoản của bạn. RFC không hoạt động trên các ký tự, nó hoạt động trên byte. Dữ liệu thử nghiệm của bạn chứa các chuỗi được mã hóa bằng hex. Khi bạn giải mã chúng thành các giá trị (Unicode)String, nhiều ký tự kết quả nằm ngoài phạm vi ký tự ASCII, nghĩa là chúng phải được mã hóa Ansi giải nghĩa trước khi bạn có thể chuyển đổi thành UTF-8 chính xác (bạn không nên sử dụng tình huống này anyway).

Bạn cần thay đổi thực hiện của bạn để giải mã chuỗi hex của bạn thẳng đến TBytes thay vì (bạn có thể sử dụng Classes.HexToBin() cho rằng) để các giá trị byte chính xác được bảo quản và truyền cho HMAC, và thoát khỏi TEncoding.UTF8.GetBytes() hoàn toàn:

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; 
+0

Trong quốc phòng, UTF8.GetBytes được sử dụng vì đó là nội dung của ứng dụng cụ thể mà chúng tôi đang thực hiện theo yêu cầu - chúng tôi chưa bao giờ tương tác với bất kỳ thứ gì bên ngoài ứng dụng. Và có một tuyên bố từ chối trách nhiệm ở cuối bài viết nói rằng tôi đã không sử dụng nó chống lại dữ liệu tham chiếu. Và chúng tôi đã cải thiện trong hai năm qua :-) – shunty

+0

Thú vị. Tại một thời điểm tôi đã có một GetHMAC quá tải lấy TBytes làm tham số. Không chắc chắn nếu tôi đã sử dụng các bài kiểm tra mã hóa Hex từ RFC tại thời điểm đó, mặc dù. Nó có thể không hoạt động vì một số vấn đề Unicode. Tôi chưa bao giờ phải đối phó trực tiếp với nó như thế này trước đây. Đối với Amazon, bạn phải lấy URI, chuyển đổi nó bằng HMAC SHA1 hoặc SHA256, sau đó chuyển đổi thành Base64, sau đó URL mã hóa, sau đó thêm chữ ký vào URI gốc. Ở Delphi, nó giống như đi bộ từ một bể cá mập này sang một bể cá mập khác. Mã của thư viện .NET của Amazon sử dụng rất đơn giản bằng cách so sánh. –

+0

@shunty - Cảm ơn bài đăng gốc.Có vẻ như bình luận của tôi rằng bạn đã nói rằng bạn chưa thử nghiệm nó chống lại bất kỳ dữ liệu tham chiếu nào đã bị giảm xuống tại một số điểm trong khi chỉnh sửa. Điều đó là tốt vì tuyên bố từ chối trách nhiệm của bạn là điều khiến tôi tìm thấy RFC và cố gắng thử nghiệm mã hóa hex của họ để hoạt động. –

Các vấn đề liên quan