SHA1 hashing in Delphi XE

前端 未结 4 585
醉梦人生
醉梦人生 2020-12-09 06:24

I\'m in the process of implementing XML digital signatures. I\'m starting with little steps, so right now I want to solve the problem of SHA-1 hashing.

There are lot

相关标签:
4条回答
  • 2020-12-09 07:05

    Leonardo, i think which your problem is the UNICODE when you uses a function to hash a string you are passing a array (buffer) of bytes. so when you pass the abc string in Delphi XE, your are hashing a buffer like this 61 00 62 00 63 00 (Hex representation)

    check this sample application which uses the Windows crypto functions from the Jwscl library (JEDI Windows Security Code 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.
    

    this return

    abc AnsiString

    A9993E364706816ABA3E25717850C26C9CD0D89D

    abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq AnsiString

    84983E441C3BD26EBAAE4AA1F95129E5E54670F1 for

    abc unicode

    9F04F41A848514162050E3D68C1A7ABB441DC2B5

    abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq Unicode

    51D7D8769AC72C409C5B0E3F69C60ADC9A039014

    0 讨论(0)
  • 2020-12-09 07:05

    My Cygwin command-prompt tells me it is indeed Unicode that's confusing you:

    ~$ printf 'a\0b\0c\0' | sha1sum
    9f04f41a848514162050e3d68c1a7abb441dc2b5 *-
    ~$ printf 'abc' | sha1sum
    a9993e364706816aba3e25717850c26c9cd0d89d *-
    
    0 讨论(0)
  • 2020-12-09 07:08

    Okay, so it was Unicode issues. Just in case you want to know, this is my Unit1.pas source. You need a form with a memo and a button. Requires DCPCrypt2, LockBox2, LockBox3 and the Hashes unit.

    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.
    
    0 讨论(0)
  • 2020-12-09 07:18

    Could the expected value be for an ANSI string and the hash you are getting is for a unicode string?

    0 讨论(0)
提交回复
热议问题