2011-02-08 15 views
7

Sono in procinto di implementare firme digitali XML. Sto iniziando a piccoli passi, quindi ora voglio risolvere il problema dell'hash SHA-1.SHA1 hashing in Delphi XE

ci sono un sacco di domande su questo 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

... e probabilmente di più. Tuttavia, sto usando Delphi XE. Finora, ho provato LockBox 2 (entrambe le versioni di Songbeamer e Sourceforge), Lock Box 3, DCPCrypto2 e alcuni altri (Hashes è un'unità facile da usare che utilizza funzioni di crittografia di Windows)

Ho preparato un piccolo banco di prova che mi dà il seguente:

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' 

hash

Test 1 passes 
Test 2 passes 

Vi siete riuscito a compilare le librerie di cui ai Delphi XE e farli danno i valori appropriati? Sono particolarmente interessato alla procedura DCPCrypt2SelfTest.

Modifica: Ho aggiunto this answer con il codice sorgente fisso. Grazie a tutti per il vostro aiuto, è molto apprezzato.

+0

Senza codice di esempio la tua domanda non ha senso. –

+1

+1 per la panoramica delle librerie. Nota che l'hashing è pensato per i dati binari, non per le stringhe (la loro rappresentazione binaria dipende dalla loro codifica). Ho scritto una conclusione simile mentre scrivevo su MD5 hashing (http://wiert.wordpress.com/2009/12/11/delphi-md5-the-messagedigest_5-unit-has-been-there-since-delphi-2007 /). (Leggendo le risposte: questa era la conclusione delle risposte ). –

+0

La prossima volta inserisci del codice! –

risposta

26

Leonardo, penso che il tuo problema è il UNICODE quando si utilizza una funzione per l'hash a string si passa una matrice (buffer) di byte.così quando si passa la stringa abc in Delphi XE, vostro sono hashing un buffer come questo (rappresentazione esadecimale) 61 00 62 00 63 00

controllo questa applicazione di esempio che utilizza le funzioni crittografiche di Windows dal Jwscl library (JEDI Windows Security Codice 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. 

questo ritorno

abc AnsiString

A9993E364706816ABA3E25717850C26C9CD0D89D

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq AnsiString

84983E441C3BD26EBAAE4AA1F95129E5E54670F1 per

abc unicode

9F04F41A848514162050E3D68C1A7ABB441DC2B5

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq Unicode

51D7D8769AC72C409C5B0E3F69C60ADC9A039014

+0

Ottima risposta. Ora vedo. Immagino che ciò che mi ha dato la direzione sbagliata sia stata la funzione SelfTest di DCPCrypt2, che restituisce false. –

+0

Buon consiglio. Non sapevo che potresti usare le librerie crittografiche in Windows, usando i wrapper JWSCL. –

+0

Questo codice sorgente può essere compilato con Delphi 7? –

6

Il valore previsto può essere per una stringa ANSI e l'hash che si ottiene è per una stringa unicode?

+0

Apparentemente, questo è il caso. –

18

mio Cygwin del prompt dei comandi mi dice che è davvero Unicode che si confonde:

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

Wow. Questo è semplicemente fantastico. –

+1

@Leonardo Mi aspetto che tu sia sarcastico, ma mostra l'utilità di Cygwin per testare questo tipo di ipotesi: md5sum, sha1sum e openssl per molto altro. –

+1

No, non sono affatto sarcastico! Ho accettato la risposta di RRUZ perché è più completa, ma questa è una risposta fantastica. Grazie! –

4

Va bene, quindi è stato problemi Unicode. Nel caso volessi sapere, questa è la mia fonte Unit1.pas. Hai bisogno di un modulo con un memo e un pulsante. Richiede DCPCrypt2, LockBox2, LockBox3 e l'unità Hash.

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. 
Problemi correlati