2011-02-08 55 views
7

Estoy en el proceso de implementación de firmas digitales XML. Estoy empezando con pequeños pasos, así que ahora quiero resolver el problema del hash SHA-1.hash SHA1 en Delphi XE

Hay un montón de preguntas acerca de esto en 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

... y probablemente más. Sin embargo, estoy usando Delphi XE. Hasta ahora, he probado LockBox 2 (las versiones Songbeamer y Sourceforge), Lock Box 3, DCPCrypto2 y algunas otras (Hashes es una unidad fácil de usar que usa funciones de cifrado de Windows)

Preparé una pequeña plataforma de prueba eso me da lo siguiente:

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 

¿Ha tenido éxito en compilar las bibliotecas mencionadas en Delphi XE y hacer que se dan los valores apropiados? Estoy particularmente interesado en DCPCrypt2SelfTest procedimiento.

Editar: He agregado this answer con el código fuente fijo. Gracias a todos por su ayuda, es muy apreciado.

+0

Sin código de muestra, su pregunta no tiene sentido. –

+1

+1 para obtener una descripción general de las bibliotecas. Tenga en cuenta que el hashing está destinado a datos binarios, no para cadenas (su representación binaria depende de su codificación). Escribí una conclusión similar mientras escribía sobre hashing MD5 (http://wiert.wordpress.com/2009/12/11/delphi-md5-the-messagedigest_5unit-has-been-there-since-delphi-2007 /). (Leyendo las respuestas: esa fue la conclusión de las respuestas también ). –

+0

¡La próxima vez publica un código! –

Respuesta

26

Leonardo, creo que su problema es el UNICODE cuando utiliza una función para hash string está pasando una matriz (búfer) de bytes.por lo que cuando se pasa la cadena abc en Delphi XE, su están hashing un buffer como esto (representación hexadecimal) 61 00 62 00 63 00

cheque esta aplicación de ejemplo que utiliza las funciones de cifrado de Windows desde el Jwscl library (Código de Seguridad Lib JEDI Windows)

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. 

este retorno

abc AnsiString

A9993E364706816ABA3E25717850C26C9CD0D89D

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq AnsiString

84983E441C3BD26EBAAE4AA1F95129E5E54670F1 para

abc Unicode

9F04F41A848514162050E3D68C1A7ABB441DC2B5

abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq Unicode

51D7D8769AC72C409C5B0E3F69C60ADC9A039014

+0

Gran respuesta. Ya lo veo. Supongo que lo que me alertó en la dirección equivocada fue la función Autoprueba DCPCrypt2, que devuelve falso. –

+0

Buen consejo. No sabía que podía usar las bibliotecas de cifrado en Windows, utilizando contenedores JWSCL. –

+0

Este código fuente se puede compilar con Delphi 7? –

6

¿Podría ser el valor esperado para una cadena ANSI y el hash que está obteniendo es para una cadena Unicode?

+0

Aparentemente, ese es el caso. –

18

Mi Cygwin del símbolo del sistema me dice que es de hecho Unicode que es confuso:

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

Wow. Esto es simplemente genial. –

+1

@Leonardo Espero que sea sarcástico, pero muestra la utilidad de Cygwin para probar este tipo de hipótesis: md5sum, sha1sum y openssl para mucho más. –

+1

No, no estoy siendo sarcástico en absoluto! Acepté la respuesta de RRUZ porque es más completa, pero esta es una respuesta excelente. ¡Gracias! –

4

bien, así que era problemas Unicode. En caso de que quieras saber, esta es mi fuente de Unit1.pas. Necesita un formulario con una nota y un botón. Requiere DCPCrypt2, LockBox2, LockBox3 y la unidad 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.