Hallo Delphianer,
ich nutze zum ersten Mal
DEC in der Version 6.0. Zuvor habe ich noch nicht mit dem
DEC gearbeitet und daher auch keine Vorkenntnisse darüber. Besonders viel findet man darüber aktuell auch (noch) nicht im Netz, da die Version ja recht frisch ist. Oder ich hab falsch gesucht.
Konkret geht es mir darum, dass ich eine Verschlüsselung (und logischerweise auch Entschlüsselung) per AES machen möchte. Ich bin auch mittlerweile so weit, dass das Ver- und Entschlüsseln funktioniert, habe aber den Verdacht, dass das einfacher funktionieren muss und ich nur auf dem Schlauch stehe. Vor allem dieses dauerhafte Umwandeln von
TArray<Byte>
in
string
und umgekehrt kommt mir recht aufwendig vor. Ich vermute ich kenne einfach nur die Kniffe noch nicht die man anwenden kann.
Speichern wollte ich den verschlüsselten String nachher im Base64 Format in einer JSON Datei. Der IV für die Verschlüsselung wird einfach als Byte Array vor den eigentlichen verschlüsselten Text gehängt. Das funktioniert auch schon.
Beim Entschlüsseln bekomme ich allerdings immer den String mit #0 nach den einzelnen Chars zurück. Ich tippe hier nur auf ein Problem mit den Encoding, konnte aber mit meinen Versuchen keine Lösung erzielen.
Kann mal jemand über meine Klasse und auch die Aufrufe der Methoden drüber schauen und mir ggf. einen Tipp geben was ich besser machen kann?
Delphi-Quellcode:
unit Common.Encryption.AES;
interface
uses
Common.Interfaces.Aes, Common.Interfaces.AesKeyReader, DECCiphers, DECRandom, System.SysUtils, Logger.Interfaces,
Logger.Enumerations, Logger.Helpers, DECCipherBase, System.Classes, System.Generics.Collections;
type
TAes =
class(TInterfacedObject, IAes)
private
FAesKeyReader: IAesKeyReader;
FLogger: ILogger;
public
constructor Create(Logger: ILogger; AesKeyReader: IAesKeyReader);
function Decrypt(Cipher: TArray<Byte>):
string;
function Encrypt(PlainText:
string): TArray<Byte>;
overload;
function Encrypt(PlainText:
string; IV: TArray<Byte>): TArray<Byte>;
overload;
end;
implementation
{ TAes }
constructor TAes.Create(Logger: ILogger; AesKeyReader: IAesKeyReader);
begin
inherited Create;
FLogger := Logger;
FAesKeyReader := AesKeyReader;
end;
function TAes.Decrypt(Cipher: TArray<Byte>):
string;
const
IV_LEN = $10;
var
AES: TCipher_AES;
iv, data: TBytes;
ms: TBytesStream;
decrypted: TArray<Byte>;
begin
try
AES := TCipher_AES.Create;
try
ms := TBytesStream.Create(Cipher);
try
SetLength(iv, IV_LEN);
if (ms.
Read(iv, IV_LEN) = IV_LEN)
then begin
AES.Mode := cmCBCx;
AES.Init(FAesKeyReader.GetAesKey, iv);
SetLength(data, ms.Size - IV_LEN);
if (ms.
Read(data, ms.Size - IV_LEN) = ms.Size - IV_LEN)
then begin
decrypted := AES.DecodeBytes(data);
Result := TEncoding.
Default.GetString(decrypted);
end;
end;
finally
ms.Free;
end;
finally
AES.Free;
end;
except
on e:
Exception do begin
Result := EmptyStr;
TLogHelper.LogMessage('
Error decrypting given cipher: %s', [e.
Message], lcError, FLogger);
end;
end;
end;
function TAes.Encrypt(PlainText:
string): TArray<Byte>;
var
IV: TArray<Byte>;
begin
IV := RandomBytes($10);
Result := Encrypt(PlainText, IV);
end;
function TAes.Encrypt(PlainText:
string; IV: TArray<Byte>): TArray<Byte>;
var
AES: TCipher_AES;
Res: TArray<Byte>;
begin
try
AES := TCipher_AES.Create;
try
AES.Mode := cmCBCx;
AES.Init(FAesKeyReader.GetAesKey, IV);
Res := AES.EncodeStringToBytes(PlainText);
SetLength(Result, Length(Res) + Length(IV));
TArray.Copy<Byte>(IV, Result, 0, 0, Length(IV));
TArray.Copy<Byte>(Res, Result, 0, Length(IV), Length(Res));
finally
AES.Free;
end;
except
on e:
Exception do begin
Result :=
nil;
TLogHelper.LogMessage('
Error encrypting given string: %s', [e.
Message], lcError, FLogger);
end;
end;
end;
end.
Die Funktion
FAesKeyReader.GetAesKey()
ruft nur den AES Key ab und lädt diesen von der Festplatte. Rückgabe ist in dem Fall auch ein
TArray<Byte>
.
Der aktuelle Testschlüssel mit dem ich verschlüssele sieht so aus (Byte Folge):
C9 58 F5 C6 26 1C A9 C6 3D 55 AE 1F AE A5 03 39 07 06 2E 8F 90 FF AA 13 2C 56 5E 32 3C 83 B3 48
.
Input ist das Wort
TestString
welches im Zwischenschritt vor dem Base64Encode Aufruf (also nur mit der AES Verschlüsselung) die folgende Byte-Folge zurückgibt:
F3 CA 54 23 0C DF 17 72 C1 94 5D 17 07 4F 8D 14 8A DF 7B 8C 71 D1 92 BD 4B 69 54 75 F1 A9 BF 2E 5B F0 66 E9
.
Der verwendete InitVector sieht so aus:
F3 CA 54 23 0C DF 17 72 C1 94 5D 17 07 4F 8D 14
.
Base64Encoded sieht das dann so aus:
88pUIwzfF3LBlF0XB0+NFIrfe4xx0ZK9S2lUdfGpvy5b8Gbp
.
Wenn ich den Base64 String nun wieder zurückwandele und das Ergebnis von
FAes.Decode()
zurück kommt, dann erhalte ich dieses Ergebnis:
'T'#0'e'#0's'#0't'#0'S'#0't'#0'r'#0'i'#0'n'#0'g'#0
.
Also den korrekten String nur eben mit #0 nach jedem einzelnen Char.
Der Aufruf der Methoden geschieht damit. Und hier vermute ich mein Problem und denke auch, dass das einfacher gehen müsste.
FAes
ist eine Instanz vom Typ
IAes
.
Delphi-Quellcode:
var
s: string;
Base64Decoded: TArray<Byte>;
Result: string;
begin
s := TEncoding.Default.GetString(TNetEncoding.Base64.Encode(FAes.Encrypt('TestString')));
Base64Decoded := TNetEncoding.Base64.Decode(TEncoding.Default.GetBytes(s));
Result := FAes.Decrypt(Base64Decoded);
end;