在 Delphi 中编译为 32 位或 64 位时,MD5 base64 哈希值不同 - 如何使它们相同?
MD5 base64 hash is different when compiled in Delphi as 32-bit or 64-bit - how can I make them the same?
我正在使用 Delphi XE2 和以下代码来创建 MD5 base64 哈希以与亚马逊 MWS 一起使用。如果我为 32 位 Windows 编译它,它会工作,但如果我为 64 位 windows 编译它,return 散列会发生变化。是什么原因造成的,我该如何更改才能使它们 return 具有相同的哈希值?
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;
提前致谢。
编辑:
我在下面的测试中使用了上面的函数;
procedure Button1Click(Sender: TObject);
begin
Edit2.Text := getMd5HashString(Edit1.Text);
end;
我路过
<?xml version="1.0" encoding="utf-8"?>
作为字符串,只是为了测试。如果我使用 Windows 32 位目标平台编译程序,returned 哈希为;
I3pK/R+hpYOKY1IQRviZbQ==
而如果我使用 Windows 64 位目标平台编译程序,我得到;
bmkkAOXGhLdDFCUuNBuSxw==
我希望这能回答你大卫?
Edit2: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.
那是我的开始尝试。根据下面大卫的建议,我将其更改为;
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.
不幸的是,结果相同。
Win32 = I3pK/R+hpYOKY1IQRviZbQ==
Win64 = bmkkAOXGhLdDFCUuNBuSxw==
我把题中的摘录变成了这个完整的程序:
{$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.
我正在使用 Indy 执行所有转换:文本到 UTF-8 字节、MD5 散列和 base64 编码。但是您应该为此使用任何库,因为它们都应该提供相同的输出。
此程序为 32 位和 64 位生成相同的输出,正如预期的那样:
I3pK/R+hpYOKY1IQRviZbQ==
虽然您报告了不同的行为,但可能是什么原因造成的?我可以想到以下可能的解释:
- 您实际上并没有将相同的输入值传递给两个版本中的函数。
TEncoding.UTF8.GetBytes
有缺陷。
TIdHashMessageDigest5.HashBytes
有缺陷。
Data.Cloud.CloudAPI.EncodeBytes64
有缺陷。
无论如何,我认为使用 Data.Cloud.CloudAPI
执行 base64 编码没有任何意义,尽管我没有理由相信它不起作用。由于您已经在使用 Indy 库,因此统一执行此操作更有意义。
从这里我无法判断以上哪种解释是您报告的原因。您应该能够进一步调试以找出答案。查看流程中每个步骤的输出,找出行为发生变化的地方。
更新: 我现在设法重现了错误,但只能使用 XE2 附带的 Indy 版本。我在最初的实验中使用的是更新版本的 Indy。
问题似乎是我列表中的第 3 项。这在 x64 编译器下给出了错误的结果。
您应该通过寻找不同的 MD5 实现来解决问题。我的建议是通过升级 Indy 来做到这一点。
我正在使用 Delphi XE2 和以下代码来创建 MD5 base64 哈希以与亚马逊 MWS 一起使用。如果我为 32 位 Windows 编译它,它会工作,但如果我为 64 位 windows 编译它,return 散列会发生变化。是什么原因造成的,我该如何更改才能使它们 return 具有相同的哈希值?
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;
提前致谢。
编辑:
我在下面的测试中使用了上面的函数;
procedure Button1Click(Sender: TObject);
begin
Edit2.Text := getMd5HashString(Edit1.Text);
end;
我路过
<?xml version="1.0" encoding="utf-8"?>
作为字符串,只是为了测试。如果我使用 Windows 32 位目标平台编译程序,returned 哈希为;
I3pK/R+hpYOKY1IQRviZbQ==
而如果我使用 Windows 64 位目标平台编译程序,我得到;
bmkkAOXGhLdDFCUuNBuSxw==
我希望这能回答你大卫?
Edit2: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.
那是我的开始尝试。根据下面大卫的建议,我将其更改为;
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.
不幸的是,结果相同。
Win32 = I3pK/R+hpYOKY1IQRviZbQ==
Win64 = bmkkAOXGhLdDFCUuNBuSxw==
我把题中的摘录变成了这个完整的程序:
{$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.
我正在使用 Indy 执行所有转换:文本到 UTF-8 字节、MD5 散列和 base64 编码。但是您应该为此使用任何库,因为它们都应该提供相同的输出。
此程序为 32 位和 64 位生成相同的输出,正如预期的那样:
I3pK/R+hpYOKY1IQRviZbQ==
虽然您报告了不同的行为,但可能是什么原因造成的?我可以想到以下可能的解释:
- 您实际上并没有将相同的输入值传递给两个版本中的函数。
TEncoding.UTF8.GetBytes
有缺陷。TIdHashMessageDigest5.HashBytes
有缺陷。Data.Cloud.CloudAPI.EncodeBytes64
有缺陷。
无论如何,我认为使用 Data.Cloud.CloudAPI
执行 base64 编码没有任何意义,尽管我没有理由相信它不起作用。由于您已经在使用 Indy 库,因此统一执行此操作更有意义。
从这里我无法判断以上哪种解释是您报告的原因。您应该能够进一步调试以找出答案。查看流程中每个步骤的输出,找出行为发生变化的地方。
更新: 我现在设法重现了错误,但只能使用 XE2 附带的 Indy 版本。我在最初的实验中使用的是更新版本的 Indy。
问题似乎是我列表中的第 3 项。这在 x64 编译器下给出了错误的结果。
您应该通过寻找不同的 MD5 实现来解决问题。我的建议是通过升级 Indy 来做到这一点。