Einzelnen Beitrag anzeigen

KaiW

Registriert seit: 5. Feb 2016
6 Beiträge
 
Delphi XE7 Architect
 
#1

DXE7+Indy: HMAC SHA256 - Encoding

  Alt 16. Okt 2016, 13:01
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
  Mit Zitat antworten Zitat