2011-02-08 74 views
7

Tôi đang trong quá trình triển khai chữ ký số XML. Tôi bắt đầu với các bước nhỏ, vì vậy ngay bây giờ tôi muốn giải quyết vấn đề băm SHA-1.Hàm băm SHA1 trong Delphi XE

Có rất nhiều câu hỏi về vấn đề này trong SO:

  1. Digitially Sign Key with Lockbox
  2. Encryption library for Delphi
  3. Convert this php digital signing to Delphi
  4. Delphi: is there a version of LockBox for Delphi-XE
  5. Delphi 2010 Cryptography libraries

... và có thể nhiều hơn nữa. Tuy nhiên, tôi đang sử dụng Delphi XE. Cho đến nay, tôi đã thử LockBox 2 (cả hai phiên bản Songbeamer và Sourceforge), Lock Box 3, DCPCrypto2 và một số khác (Hashes là một đơn vị dễ sử dụng sử dụng các chức năng mã hóa Windows)

Tôi đã chuẩn bị một giàn khoan nhỏ mà mang lại cho tôi những điều sau đây:

LockBox2

FAILED: 1 ('abc') 
     Got: '9f04f41a848514162050e3d68c1a7abb441dc2b5' 
    Expected: 'a9993e364706816aba3e25717850c26c9cd0d89d' 
FAILED: 2 ('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq') 
     Got: '51d7d8769ac72c409c5b0e3f69c60adc9a039014' 
    Expected: '84983e441c3bd26ebaae4aa1f95129e5e54670f1' 

LockBox3

FAILED: 1 ('abc') 
     Got: '9f04f41a848514162050e3d68c1a7abb441dc2b5' 
    Expected: 'a9993e364706816aba3e25717850c26c9cd0d89d' 
FAILED: 2 ('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq') 
     Got: '51d7d8769ac72c409c5b0e3f69c60adc9a039014' 
    Expected: '84983e441c3bd26ebaae4aa1f95129e5e54670f1' 

DCPCrypto2

FAILED: 1 ('abc') 
     Got: '9f04f41a848514162050e3d68c1a7abb441dc2b5' 
    Expected: 'a9993e364706816aba3e25717850c26c9cd0d89d' 
FAILED: 2 ('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq') 
     Got: '51d7d8769ac72c409c5b0e3f69c60adc9a039014' 
    Expected: '84983e441c3bd26ebaae4aa1f95129e5e54670f1' 

Hashes

Test 1 passes 
Test 2 passes 

Bạn đã thành công trong việc biên soạn các thư viện nêu dưới Delphi XE và làm cho họ cung cấp cho các giá trị thích hợp? Tôi đặc biệt quan tâm đến thủ tục DCPCrypt2SelfTest.

Chỉnh sửa: Tôi đã thêm this answer với mã nguồn cố định. Cảm ơn tất cả vì sự giúp đỡ của bạn, nó được đánh giá cao nhất.

+0

Nếu không có mã mẫu, câu hỏi của bạn là vô nghĩa. –

+1

+1 để biết tổng quan về thư viện. Lưu ý rằng băm có nghĩa là cho dữ liệu nhị phân, không cho các chuỗi (biểu diễn nhị phân của chúng phụ thuộc vào mã hóa của chúng). Tôi đã viết một kết luận tương tự trong khi [viết trên băm MD5] (http://wiert.wordpress.com/2009/12/11/delphi-md5-the-messagedigest_5-unit-has-been-there-since-delphi-2007 /). (Đọc câu trả lời: đó là kết luận của các câu trả lời quá ). –

+0

Tiếp theo thời gian đăng một số mã! –

Trả lời

26

Leonardo, tôi nghĩ vấn đề của bạn là UNICODE khi bạn sử dụng hàm để băm string bạn đang chuyển một mảng (bộ đệm) byte.vì vậy khi bạn vượt qua abc chuỗi trong Delphi XE, bạn được băm một bộ đệm như 61 00 62 00 63 00 (Hex đại diện) này

kiểm tra ứng dụng mẫu này trong đó sử dụng các chức năng crypto Windows từ Jwscl library (JEDI Windows Security Mã Lib)

program Jwscl_TestHash; 

{$APPTYPE CONSOLE} 

uses 
    JwsclTypes, 
    JwsclCryptProvider, 
    Classes, 
    SysUtils; 

function GetHashString(Algorithm: TJwHashAlgorithm; Buffer : Pointer;Size:Integer) : AnsiString; 
var 
    Hash: TJwHash; 
    HashSize: Cardinal; 
    HashData: Pointer; 
    i  : Integer; 
begin 
    Hash := TJwHash.Create(Algorithm); 
    try 
    Hash.HashData(Buffer,Size); 
    HashData := Hash.RetrieveHash(HashSize); 
    try 
     SetLength(Result,HashSize*2); 
     BinToHex(PAnsiChar(HashData),PAnsiChar(Result),HashSize); 
    finally 
     TJwHash.FreeBuffer(HashData); 
    end; 
    finally 
    Hash.Free; 
    end; 
end; 


function GetHashSHA(FBuffer : AnsiString): AnsiString; 
begin 
    Result:=GetHashString(haSHA,@FBuffer[1],Length(FBuffer)); 
end; 

function GetHashSHA_Unicode(FBuffer : String): String; 
begin 
    Result:=GetHashString(haSHA,@FBuffer[1],Length(FBuffer)*SizeOf(Char)); 
end; 

begin 
try 
    Writeln(GetHashSHA('abc')); 
    Writeln(GetHashSHA('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')); 
    Writeln(GetHashSHA_Unicode('abc')); 
    Writeln(GetHashSHA_Unicode('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')); 
    Readln; 
except 
    on E:Exception do 
    begin 
     Writeln(E.Classname, ':', E.Message); 
     Readln; 
    end; 
end; 

end. 

trở lại này

abc AnsiString

A9993E364706816ABA3E25717850C26C9CD0D89D

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq AnsiString

84983E441C3BD26EBAAE4AA1F95129E5E54670F1 cho

abc unicode

9F04F41A848514162050E3D68C1A7ABB441DC2B5

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq Unicode

51D7D8769AC72C409C5B0E3F69C60ADC9A039014

+0

Câu trả lời hay. Tôi hiểu rồi. Tôi đoán những gì nghiêng tôi đi sai hướng là chức năng SelfTest DCPCrypt2, trả về false. –

+0

Mẹo hay. Tôi không biết bạn có thể sử dụng các thư viện mật mã trong Windows, sử dụng trình bao bọc JWSCL. –

+0

Mã nguồn này có thể được biên dịch với Delphi 7? –

6

Giá trị kỳ vọng có thể là một chuỗi ANSI và băm bạn nhận được là cho chuỗi unicode không?

+0

Rõ ràng, đó là trường hợp. –

18

My Cygwin nhắc lệnh nói với tôi nó thực sự là Unicode đó là khó hiểu bạn:

~$ printf 'a\0b\0c\0' | sha1sum 
9f04f41a848514162050e3d68c1a7abb441dc2b5 *- 
~$ printf 'abc' | sha1sum 
a9993e364706816aba3e25717850c26c9cd0d89d *- 
+1

Chà. Điều này thật tuyệt. –

+1

@Leonardo Tôi hy vọng bạn đang châm biếm, nhưng nó cho thấy tiện ích của Cygwin để thử nghiệm các loại giả thuyết này - md5sum, sha1sum và openssl cho nhiều hơn nữa. –

+1

Không, tôi không hề mỉa mai! Tôi chấp nhận câu trả lời của RRUZ vì nó hoàn chỉnh hơn, nhưng đây là một câu trả lời tuyệt vời. Cảm ơn! –

4

Được rồi, vì vậy nó là vấn đề Unicode. Chỉ trong trường hợp bạn muốn biết, đây là nguồn Unit1.pas của tôi. Bạn cần một biểu mẫu với một bản ghi nhớ và một nút. Yêu cầu DCPCrypt2, LockBox2, LockBox3 và đơn vị Hashes.

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, LbCipher, LbClass, StdCtrls, DCPcrypt2, DCPsha1, Hashes, 
    uTPLb_CryptographicLibrary, uTPLb_BaseNonVisualComponent, uTPLb_Hash; 

type 
    THashProc = reference to procedure(src: AnsiString; var output: AnsiString); 

    TForm1 = class(TForm) 
    Memo1: TMemo; 
    btnTest: TButton; 
    function Display(Buf: TBytes): String; 

    procedure LockBox2Test; 
    procedure LockBox3Test; 
    procedure DCPCrypto2Test; 
    procedure HashesTest; 
    procedure btnTestClick(Sender: TObject); 
    private 
    { Private declarations } 
    procedure RunTests(Name: String; HashFunc: THashProc); 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

uses uTPLb_StreamUtils; 

{$R *.dfm} 

procedure TForm1.btnTestClick(Sender: TObject); 
begin 
    LockBox2Test; 
    LockBox3Test; 
    DCPCrypto2Test; 
    HashesTest; 
end; 

procedure TForm1.DCPCrypto2Test; 
begin 
    RunTests('DCPCrypto2', procedure(src: AnsiString; var output: AnsiString) 
    var 
    Digest: TSHA1Digest; 
    Bytes : TBytes; 
    SHA1 : TDCP_sha1; 
    begin 
    SHA1 := TDCP_sha1.Create(nil); 
    SHA1.Init; 
    SHA1.UpdateStr(src); 
    SHA1.Final(Digest); 
    SHA1.Destroy; 
    SetLength(Bytes, 20); 
    Move(Digest, Bytes[0], 20); 
    output := Form1.Display(Bytes); 
    end); 
end; 

function TForm1.Display(Buf: TBytes): String; 
var 
    i: Integer; 
begin 
    Result := ''; 
    for i := 0 to 19 do 
    Result := Result + Format('%0.2x', [Buf[i]]); 
    Result := LowerCase(Trim(Result)); 
end; 

procedure TForm1.HashesTest; 
begin 
    RunTests('Hashes', procedure(src: AnsiString; var output: AnsiString) 
    begin 
    output := CalcHash2(src, haSHA1) 
    end) 
end; 

procedure TForm1.LockBox2Test; 
begin 
    RunTests('LockBox2', procedure(src: AnsiString; var output: AnsiString) 
    var 
     Digest: TSHA1Digest; 
     Bytes : TBytes; 
     SHA1 : TLbSHA1; 
    begin 
     SHA1 := TLbSHA1.Create(nil); 
     SHA1.HashStringA(src); 
     SHA1.GetDigest(Digest); 
     SHA1.Destroy; 
     SetLength(Bytes, 20); 
     Move(Digest, Bytes[0], 20); 
     output := Form1.Display(Bytes); 
    end); 
end; 

procedure TForm1.LockBox3Test; 
begin 
    RunTests('LockBox3', procedure(src: AnsiString; var output: AnsiString) 
    var 
     Digest: TSHA1Digest; 
     bytes : TBytes; 
     P, Sz: integer; 
     aByte: byte; 
     s: string; 
     SHA1 : THash; 
     Lib : TCryptographicLibrary; 
    begin 
     Lib := TCryptographicLibrary.Create(nil); 
     SHA1 := THash.Create(nil); 
     SHA1.CryptoLibrary := Lib; 
     SHA1.HashId := 'native.hash.SHA-1'; 
     SHA1.Begin_Hash; 
     SHA1.HashAnsiString(src); 
     if not assigned(SHA1.HashOutputValue) then 
      output := 'nil' 
     else 
     begin 
     SetLength(Bytes, 20); 
     Sz := SHA1.HashOutputValue.Size; 
     if Sz <> 20 then 
      output := Format('wrong size: %d', [Sz]) 
     else 
     begin 
      P := 0; 
      SHA1.HashOutputValue.Position := 0; 
      while SHA1.HashOutputValue.Read(aByte, 1) = 1 do 
      begin 
      bytes[P] := aByte; 
      Inc(P); 
      end; 
      output := Form1.Display(Bytes); 
     end; 
     end; 
     SHA1.Destroy; 
     Lib.Destroy; 
    end) 
end; 

procedure TForm1.RunTests(Name: String; HashFunc: THashProc); 
var 
    i: Integer; 
    Tests: array [1 .. 2, 1 .. 2] of AnsiString; 
    src, res: AnsiString; 
    expected: String; 
begin 
    // http://www.nsrl.nist.gov/testdata/ 
    Tests[1][1] := 'abc'; 
    Tests[1][2] := 'a9993e364706816aba3e25717850c26c9cd0d89d'; 

    Tests[2][1] := 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'; 
    Tests[2][2] := '84983e441c3bd26ebaae4aa1f95129e5e54670f1'; 

    Memo1.Lines.Add(''); 
    Memo1.Lines.Add('**' + Name + '**'); 
    Memo1.Lines.Add(''); 

    for i := 1 to 2 do 
    begin 
    src := Tests[i][1]; 
    expected := Tests[i][2]; 
    HashFunc(src, res); 
    res := Trim(LowerCase(res)); 
    if res = expected then 
    begin 
     Memo1.Lines.Add(Format(' Test %d passes', [i])) 
    end 
    else 
    begin 
     Memo1.Lines.Add(Format(' FAILED: %d (''%s'') ', [i, src])); 
     Memo1.Lines.Add(Format('   Got: ''%s''', [res])); 
     Memo1.Lines.Add(Format('  Expected: ''%s''', [expected])); 
    end; 
    end; 

end; 

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