I am using Delphi XE2 and the below code to create an MD5 base64 hash to use with Amazon MWS. It works if I compile it for 32-bit Windows, but if I compile for 64-bit windows the return hash changes. What is causing this and how can I change this so that they return the same hash?
function getMd5HashString(value: string): string;
var
MessageDigest: TIdHashMessageDigest5;
Content: TBytes;
begin
Content := TEncoding.UTF8.GetBytes(value);
MessageDigest:=TIdHashMessageDigest5.Create;
Result:=Data.Cloud.CloudAPI.EncodeBytes64(MessageDigest.HashBytes(Content));
end;
Thansk in advance.
Edit:
I am using the above function in the following test;
procedure Button1Click(Sender: TObject);
begin
Edit2.Text := getMd5HashString(Edit1.Text);
end;
I am passing
<?xml version="1.0" encoding="utf-8"?>
as the string, just to test with. If I compile the program with a Target Platform of Windows 32-bit the returned hash is;
I3pK/R+hpYOKY1IQRviZbQ==
Whereas if I compile the program with a Target Platform of Windows 64-bit I get;
bmkkAOXGhLdDFCUuNBuSxw==
I hope that answers you David?
Edit2: Full program as suggested by David;
unit ContentHashTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.Cloud.CloudAPI, IdGlobal, IdHash, IdHashMessageDigest,
IdCoder, IdCoderMIME, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private
function getMd5HashString(value: string): string;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text := getMd5HashString(Edit1.Text);
end;
function TForm1.getMd5HashString(value: string): string;
var
MessageDigest: TIdHashMessageDigest5;
Content: TBytes;
begin
Content := TEncoding.UTF8.GetBytes(value);
MessageDigest:=TIdHashMessageDigest5.Create;
Result:=Data.Cloud.CloudAPI.EncodeBytes64(MessageDigest.HashBytes(Content));
end;
end.
That was my starting attempt. After David's suggestion below I changed this to;
unit ContentHashTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdGlobal, IdHash, IdHashMessageDigest,
IdCoder, IdCoderMIME, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private
function getMd5HashString(value: string): string;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text := getMd5HashString(Edit1.Text);
end;
function TForm1.getMd5HashString(value: string): string;
var
MessageDigest: TIdHashMessageDigest5;
Content: TIdBytes;
begin
Content := TIdTextEncoding.UTF8.GetBytes(value);
MessageDigest := TIdHashMessageDigest5.Create;
try
Result := TIdEncoderMIME.EncodeBytes(MessageDigest.HashBytes(Content));
finally
MessageDigest.Free;
end;
end;
end.
Unfortunately with the same differing results.
Win32 = I3pK/R+hpYOKY1IQRviZbQ==
Win64 = bmkkAOXGhLdDFCUuNBuSxw==
I turned the extracts in the question into this complete program:
{$APPTYPE CONSOLE}
uses
SysUtils,
IdGlobal,
IdCoderMIME,
IdHashMessageDigest;
function getMd5HashString(value: string): string;
var
MessageDigest: TIdHashMessageDigest5;
Content: TIdBytes;
begin
//Content := TIdTextEncoding.UTF8.GetBytes(value); // for older versions of Indy
Content := IndyTextEncoding_UTF8.GetBytes(value);
MessageDigest := TIdHashMessageDigest5.Create;
try
Result := TIdEncoderMIME.EncodeBytes(MessageDigest.HashBytes(Content));
finally
MessageDigest.Free;
end;
end;
begin
Writeln(getMd5HashString('<?xml version="1.0" encoding="utf-8"?>'));
Readln;
end.
I'm using Indy to perform all of the conversions: text to UTF-8 bytes, MD5 hashing, and the base64 encoding. But you should use any libraries for this, since they should all give the same output.
This program produces the same output for 32 and 64 bit, as would be expected:
I3pK/R+hpYOKY1IQRviZbQ==
You report different behaviour though, so what could be the cause? I can think of the following possible explanations:
TEncoding.UTF8.GetBytes
is defective.TIdHashMessageDigest5.HashBytes
is defective.Data.Cloud.CloudAPI.EncodeBytes64
is defective.In any case, I don't see any sense in using Data.Cloud.CloudAPI
to perform base64 encoding, although I have no reason to believe that it does not work. Since you are already using the Indy library, it makes more sense to do that uniformly.
I cannot tell from here which of the above explanations is the cause of what you report. You should be able to debug this further to find out. Look at the output of each step in the process to figure out where the behaviour varies.
Update: I've managed now to reproduce the error, but only by using the version of Indy that ships with XE2. I was using a more up-to-date version of Indy in my initial experiments.
The problem appears to be item 3 in my list. This gives incorrect results under the x64 compiler.
You should solve the problem by finding a different MD5 implementation. My recommendation is to do this by upgrading Indy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With