Hallo zusammen,
das eigentliche Kernproblem: Ich möchte die PHP-Funktionen hash_hmac und base64_encode in Delphi abbilden um das Datum '1234567890' mit dem Schlüssel 'ABCDEFG' zu signieren und das Ergebnis anschließend base64 kodieren.
In PHP sieht das ganze folgendermaßen aus:
Code:
echo base64_encode(hash_hmac('sha256', '1234567890', 'ABCDEFG', TRUE));
Ausgabe: aRGlc3RY1pKmKX0hvorkVKNcPigiJX2rksqXzlAeCLg=
Ich habe die
Indy-Klasse TIdHMACSHA256 auserkoren, dies für mich zu tun:
Delphi-Quellcode:
uses
IdHash, IdHashSHA, IdHMACSHA1, IdSSLOpenSSL, IdGlobal, IdCoderMIME;
function GenerateSignature(const AKey, AData: string): string;
var
AHMAC: TIdBytes;
begin
IdSSLOpenSSL.LoadOpenSSLLibrary;
With TIdHMACSHA256.Create do
try
Key:= ToBytes(AKey, IndyTextEncoding_UTF16LE);
AHMAC:= HashValue(ToBytes(AData, IndyTextEncoding_UTF16LE));
Result:= TIdEncoderMIME.EncodeBytes(AHMAC);
finally
Free;
end;
end;
Rückgabewert: H3eBWh0jKF0WZIK+NcYdwXRQAWrMrNLfOM3/mBU0XpU=
Auffällig ist, dass der Rückgabewert bei
Memo.Lines.Text:= GenerateSignature('1234567890', 'ABCDEFG');
nicht mit dem über PHP ermittelten Wert übereinstimmt.
Meine Kernfrage lautet also: Warum ist das so und wie bekomme ich den gleichen Wert, den ich über die PHP-Funktionen erhalte?
Mein bisheriger Ansatz:
Ich vermute ein Problem mit den Zeichensätzen.
Ich habe verstanden, dass der Datentyp "string" bei Delphi XE7 dem Typ "UnicodeString" entspricht. UnicodeString arbeitet intern mit 2 Byte großen Zeichen (also 16bit) und ist UTF16 kodiert.
http://docwiki.embarcadero.com/RADSt...Types_(Delphi).
Die
Indy-Funktion "ToBytes" erwartet einen UnicodeString, sowie eine Zeichensatzangabe. Wird keine angegeben, wird
ASCII verwendet, was ja zu Datenverlust führen könnte/wird. Also gebe ich UTF16 an. Da bei UTF16 zwischen BE (Big-Endian) und LE(Little-Endian) gewählt werden muss, habe ich mich für UTF16LE entschieden, da einerseits in einigen Artikeln im Netz LE als von "aktuellen Maschinen" verwendet bezeichnet wurde und andererseits Delphi's eigene Encodings "
Unicode" und "BigEndianUnicode" heißen, was impliziert, dass
Unicode (also LE) der Standard ist. Ich hatte hier auch bereits mit anderen Zeichensätzen experimentiert, jedoch ohne Erfolg.
Da
TIdEncoderMIME.EncodeBytes(AHMAC);
bei Übergabe der IdBytes als Parameter zunächst alles in einen Stream schreibt und diesen dann mit Charset 8bit wieder ausliest, vermute ich hier ebenfalls eine Fehlerquelle. Daher habe ich stattdessen auch
Delphi-Quellcode:
Result:= BytesToString(AHMAC, IndyTextEncoding_UTF16LE);
Result:= TIdEncoderMIME.EncodeString(Result, IndyTextEncoding_UTF16LE);
probiert. Leider ebenfalls ohne Erfolg.
Für jedwede Hilfe bin ich dankbar.
Kai