MD5 Hashing in Delphi 2009

14,212

Solution 1

Your library is not Unicode aware. Just passing it an AnsiString won't be enough because it probably uses strings internally to store data.

You could try to update that library, wait for the author to update it, or just use the MessageDigest_5.pas that ships with Delphi 2009. It is in the source\Win32\soap\wsdlimporter folder, which you will need to either add to your path, or explicitly include it in your project.

Here is some sample code using it in Delphi 2009:

uses Types, MessageDigest_5;

procedure TForm16.Edit1Change(Sender: TObject);
var
  MD5: IMD5;
begin
  MD5 := GetMD5;
  MD5.Init;
  MD5.Update(TByteDynArray(RawByteString(Edit1.Text)), Length(Edit1.Text));
  Edit2.Text := LowerCase(MD5.AsString);
end;

And you are in business:

MD5(123456) = e10adc3949ba59abbe56e057f20f883e

You could wrap it in a simple function call if you wanted to. It is important you cast to a RawByteString before casting to a TByteDynArray since the RawByteString cast drops all the extra Unicode characters. Granted if the edit contains Unicode characters then you could end up with bad data.

Keep in mind that GetMD5 is returning an interface, so it is reference counted, etc.

Merry Christmas!

Solution 2

Have you checked that your library has been correctly updated for D2009 and unicodification? I kinda doubt the same code would do D7/D2007 and D2009 for this sort of things.

Solution 3

It is obvious that your lib is not unicode enabled.

Convert your string to AnsiString or RawByteString or UTF8String by declaring temp AnsiString and assign your uniode string to it.

Note that if you are using unicode specific chars that can't be translated to single codepage, you should convert your string to UTF8.

Then call MD5(PAnsiChar(YourTempString)).

Check that your lib may have PWideChar or UNICODE declarations, to skip this.

Solution 4

If you have wcrypt2.pas, use this function.

function md5ansi(const Input: AnsiString): AnsiString;
var
  hCryptProvider: HCRYPTPROV;
  hHash: HCRYPTHASH;
  bHash: array[0..$7f] of Byte;
  dwHashBytes: Cardinal;
  pbContent: PByte;
  i: Integer;
begin
  dwHashBytes := 16;
  pbContent := Pointer(PAnsiChar(Input));
  Result := '';

  if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
  begin
    if CryptCreateHash(hCryptProvider, CALG_MD5, 0, 0, @hHash) then
    begin
      if CryptHashData(hHash, pbContent, Length(Input) * sizeof(AnsiChar), 0) then
      begin
        if CryptGetHashParam(hHash, HP_HASHVAL, @bHash[0], @dwHashBytes, 0) then
        begin
          for i := 0 to dwHashBytes - 1 do
          begin
            Result := Result + AnsiString(Format('%.2x', [bHash[i]]));
          end;
        end;
      end;
      CryptDestroyHash(hHash);
    end;
    CryptReleaseContext(hCryptProvider, 0);
  end;

  Result := AnsiString(AnsiLowerCase(String(Result)));
end;
Share:
14,212
Admin
Author by

Admin

Updated on June 19, 2022

Comments

  • Admin
    Admin almost 2 years

    In borland delphi 7 and even in delphi 2007 everything worked, but in delphi 2009 it just returns the wrong hash!

    I use wcrypt2 script (http://pastebin.com/m2f015cfd)

    Just have a look:

    string : "123456"

    hash:

    Delphi 7 : "e10adc3949ba59abbe56e057f20f883e" - real hash.
    Delphi 2007 : "e10adc3949ba59abbe56e057f20f883e" - real hash too.
    And... Delphi 2009 : "5fa285e1bebe0a6623e33afc04a1fbd5" - WTF??

    I've tried a lot of md5 scripts, but delphi 2009 does the same with all of them. Any help? Thanks.

  • jachguate
    jachguate over 13 years
    @JW Kim, welcome to StackOverflow. Please, take some time reading the faq. If you have previous experience with forums or newsgoups, you'll notice the site works in a different way. You're answering a rather old question with an accepted answer, thus it is valid, it is not used. To publish source code you have to indent it by 4 space characters to make it look source code. :)
  • David Heffernan
    David Heffernan over 9 years
    The casts here are completely bogus. You cannot reasonably cast a UnicodeString to RawByteString. And you absolutely cannot cast RawByteString to byte array. This answer is so badly wrong, and so erroneously voted on that it should simply be deleted. The right solution uses TEncoding.GetBytes.