![]() |
Re: [DEC] WideString ver/entschlüsseln
Ich weiß nicht wie der Typ Binary definiert ist, aber meine ganzen Erklärungen bezogen sich nur darauf, dass du bei folgendem Konstrukt
Delphi-Quellcode:
etwas beachten musst: Du übergibst damit nicht den String! Du musst hier entweder den ersten Buchstaben des Strings angeben - oder, wenn die Funktion EncodeBinary() einen Pointer entgegen nimmt, eine Typkonvertierung auf PWideChar machen.
cipher.EncodeBinary(Text)
Und deine o.g. Funktion hat noch string im Aufruf und führt damit eine Autokonvertierung beim Aufruf durch (wenn mit WideString aufgerufen). Auch Frage ich mich gerade, woher die Methode EncodeBinary() die Länge der Binarydaten ermittelt. Diese müsstest du doch irgendwo mit angeben. |
Re: [DEC] WideString ver/entschlüsseln
Hi,
also als erstes probiere mal diese beiden Funktionen:
Delphi-Quellcode:
die Konstanten kannst du an deine Bedürfnisse anpassen, also Cipher-/Hash-/Formatklasse usw.
var
ACipherClass: TDECCipherClass = TCipher_Blowfish; ACipherMode: TCipherMode = cmCFS8; AHashClass: TDECHashClass = THash_SHA1; ATextFormat: TDECFormatClass = TFormat_MIME64; AKDFIndex: LongWord = 1; function Encrypt(const AText: String; const APassword: String): String; var ASalt: Binary; AData: Binary; APass: Binary; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := RandomBinary(16); APass := ValidHash(AHashClass).KDFx(APassword, ASalt, KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); AData := ASalt + EncodeBinary(AText) + CalcMAC; Result := ValidFormat(ATextFormat).Encode(AData); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(APass); end; end; function Decrypt(const AText: String; const APassword: String): String; var ASalt: Binary; AData: Binary; ACheck: Binary; APass: Binary; ALen: Integer; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := ValidFormat(ATextFormat).Decode(AText); ALen := Length(ASalt) -16 -BufferSize; AData := System.Copy(ASalt, 17, ALen); ACheck := System.Copy(ASalt, ALen +17, BufferSize); SetLength(ASalt, 16); APass := ValidHash(AHashClass).KDFx(APassword, ASalt, KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); Result := DecodeBinary(AData); if ACheck <> CalcMAC then raise Exception.Create('Invalid data'); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(ACheck); ProtectBinary(APass); end; end; Das ist noch nicht WideString kompatibel, erstmal wollen wir die einfach Sache zum Laufen bringen. Gruß Hagen Achso: der Datentyp "Binary" ist einfach ein redefinierter LongString und solll im Namen anzeigen das dieser String eben als Container für binäre Daten herhalten muß. |
Re: [DEC] WideString ver/entschlüsseln
als nächstes wandeln wir diese Funktionen in WideString Funktionen um
Delphi-Quellcode:
Beachte dabei das das Datenformat der verschlüsselten Daten als normaler LongString verarbeitet wird, bei MIME64 Format ist dies kein Problem da dieses auf Grund des Zeichensatzes für beide Datentypen, LongString und WideString, kompatibel ist.
var
ACipherClass: TDECCipherClass = TCipher_Rijndael; ACipherMode: TCipherMode = cmCBCx; AHashClass: TDECHashClass = THash_SHA1; ATextFormat: TDECFormatClass = TFormat_MIME64; AKDFIndex: LongWord = 1; function Encrypt(const AText: WideString; const APassword: WideString): String; var ASalt: Binary; AData: Binary; APass: Binary; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := RandomBinary(16); APass := ValidHash(AHashClass).KDFx(APassword[1], Length(APassword) * 2, ASalt[1], Length(ASalt), KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); SetLength(AData, Length(AText) * 2); Encode(AText[1], AData[1], Length(AData)); Result := ValidFormat(ATextFormat).Encode(ASalt + AData + CalcMAC); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(APass); end; end; function Decrypt(const AText: String; const APassword: WideString): WideString; var ASalt: Binary; AData: Binary; ACheck: Binary; APass: Binary; ALen: Integer; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := ValidFormat(ATextFormat).Decode(AText); ALen := Length(ASalt) -16 -BufferSize; AData := System.Copy(ASalt, 17, ALen); ACheck := System.Copy(ASalt, ALen +17, BufferSize); SetLength(ASalt, 16); APass := ValidHash(AHashClass).KDFx(APassword[1], Length(APassword) *2, ASalt[1], Length(ASalt), KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); Result := DecodeBinary(AData); if ACheck <> CalcMAC then raise Exception.Create('Invalid data'); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(ACheck); ProtectBinary(APass); end; end; Gruß Hagen |
Re: [DEC] WideString ver/entschlüsseln
nun können wir die komplette Funktion als WideString Funktion umbauen. Wir deklarieren die restlichen LongStrings einfach als Widestring.
Delphi-Quellcode:
Das macht aber im Grunde keinen Unterschied mehr, ausser das der verschlüsselte WideString doppelt soviel Speicher benötigt also sein Pendant LongString, und das intern die RTL eine Speicherkopieroperation zusätzlich benötigt um den LongString=Binary in einen WideString als Result, umwandeln zu können. Dh. diese Version der Funktionen ist langsammer und verbraucht auf Grund des WideString mehr Speicher. Die Funktionen der letzten beiden Postings sind also kompatibel zueinander.
var
ACipherClass: TDECCipherClass = TCipher_Rijndael; ACipherMode: TCipherMode = cmCBCx; AHashClass: TDECHashClass = THash_SHA1; ATextFormat: TDECFormatClass = TFormat_MIME64; AKDFIndex: LongWord = 1; function Encrypt(const AText: WideString; const APassword: WideString): WideString; var ASalt: Binary; AData: Binary; APass: Binary; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := RandomBinary(16); APass := ValidHash(AHashClass).KDFx(APassword[1], Length(APassword) * 2, ASalt[1], Length(ASalt), KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); SetLength(AData, Length(AText) * 2); Encode(AText[1], AData[1], Length(AData)); Result := ValidFormat(ATextFormat).Encode(ASalt + AData + CalcMAC); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(APass); end; end; function Decrypt(const AText: WideString; const APassword: WideString): WideString; var ASalt: Binary; AData: Binary; ACheck: Binary; APass: Binary; ALen: Integer; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := ValidFormat(ATextFormat).Decode(AText); ALen := Length(ASalt) -16 -BufferSize; AData := System.Copy(ASalt, 17, ALen); ACheck := System.Copy(ASalt, ALen +17, BufferSize); SetLength(ASalt, 16); APass := ValidHash(AHashClass).KDFx(APassword[1], Length(APassword) *2, ASalt[1], Length(ASalt), KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); Result := DecodeBinary(AData); if ACheck <> CalcMAC then raise Exception.Create('Invalid data'); finally Free; ProtectBinary(ASalt); ProtectBinary(AData); ProtectBinary(ACheck); ProtectBinary(APass); end; end; Gruß Hagen |
Re: [DEC] WideString ver/entschlüsseln
Hallo Hagen ;)
Danke für die kleine Einführung. Aber es gibt ein kleines Problem: Und zwar wenn ich mit der WideString-Variante Ver- und wieder entschlüssel: Ich bekomme zwar den Ursprungstext wieder heraus, aber dieser wird immer wieder durch "#0" aufgeteilt:
Delphi-Quellcode:
Zu der Decrypt-Version: Ich habe die etwas umgestaltet:
decryptedText := <Mein Widestring>
str := EncryptW(decryptedText , WideString(<Mein Password (String)>)); MessageBoxW(0, PWideChar(decryptedText), PWideChar(WideString('Titel')), MB_OK); if DecryptW(str, WideString(frmPassword.mePasswd.Text), decryptedText) then begin MessageBoxW(0, PWideChar(decryptedText), PWideChar(WideString('Titel')), MB_OK); end; Sie hat einen Var-Parameter der den String zurückgibt, und als funktionsrückgabe ob es funktioniert hat (Anstelle der Exception). Außerdem heißt sie DecryptW, da ich jetzt zwei Versionen habe ;) Zuerst steht in "decryptedText" (Typus: WideString) der korrekte WideString: z.B. ![]() Wenn ich das dann mit meinen Passwort verschlüssele (Typus: String) und das ergebnis wieder entschlüsselte steht in "decryptedText" zwar der String, nur eben ständig mit einem "#0": h#0t#0t#0p#0:#0/#0/#0w#0w#0w#0.#0g#0o#0o#0g#0l#0e#0.#0d#0e#0 Übrigens ist es für Delphi egal, ob es sich um einen WideString oder String handelt, der als Schlüssel steht. Bei beiden kommt es zu der komischen anzeige... Was mache ich nun falsch? MfG xZise |
Re: [DEC] WideString ver/entschlüsseln
Hm so aus dem Stegreif weis ich auch nicht was falsch ist. Ein WideString ist aber ein Array of WideChar und WideChar ist ein 2 Bytes Datentyp. Bei Ansicode Zeichensatz wird nur 1 Byte davon real benutzt das andere muß immer 0 sein. Also sieht es eher so aus als ob die MessageBox() einen WideString als normalen String anzeigt oder aber als ob die VCL aus einem WideString einen Wide-WideString macht. Ich habe meine obigen Funktionen dahingehend getestet das ich das WideString Resultat im Debugger View im Speicherauszug angezeigt habe. Dann wirst du sehen das das Resultat ein echter WideString ist, also 2. Bytes wobei das 2. Byte pro Zeichen immer 0 ist. Es drängt sich also der Verdacht bei mir auf das irgendwas nach der Ver/Entschlüsselung, also in der Anzeigeroutine, falsch sein muß. Nur kann ich eben in deinem Source bisher keinen Fehler sehen. Kurz gesagt: ich denke das meine Funktionen alles richtig machen und der "Fehler" ausserhalb zu suchen ist. Leider habe ich bisher nur sehr wenig mit WideString gearbeitet und somit wenig Erfahrungen mit deren Eigenheiten.
Das Passwort sollte bei einer WideString Version natürlich auch WideString sein. Das macht zwar in unseren Regionen keinen wirklichen Sinn aber bei zb. Russischen oder Chinesischen Zeichensätzen ist es sehr wichtig. Denn jedes Bit an Information innerhalb des Passwortes bedeutet Sicherheit. Würde man ein WideString Passwort direkt in Cipher.Init() benutzen in dem jedes 2. Byte #0 ist so würde das die Sicherheit wieder reduzieren. Da wir aber mit einem Salt und einer KDF quasi die binären Daten des Passwortes in einen binären kompatiblen LongString als SessionKey umwandeln, entsteht dieses Sicherheitsrisiko nicht. Die KDF arbeitet quasi so ähnlich wie eine Komprimierungsfunktion aus Sicht der verwertbaren Entropie innerhalb der Passwortdaten. Gruß Hagen Achso: ein TypCast mit PChar() oder PWideChar() wandelt einen Delphi Datentyp, der intern eine separates Feld zu Längenangabe des Strings benutzt, in einen C typischen Nullterminierten String um. Sollte im Delphi Datentyp also ein #0-Teriminator mittten im String vorkommen, was durchaus ohne Probleme mit Delphis Datentypen möglich ist, dann wird durch diesen "Typcast" bzw. der später benutzten API Funktion der Strng quasi virtuell "abgeschnitten". Die API Funktion, zb. eine MessageBox() und damit die GDI Funktion DrawText() schneitet dann in der Anzeige diese String ab. Auch alle PChar/PWideChar Kopieroperatione wie StrLen(), StrCopy() usw. arbeiten mit dem #0-Terminator und schneiden die Delphi Datentypen ab. Normalwerweise kommen in einem String/LongString/WideString im Delphi ja keine #0-Terminatoren mitten im String vor. Aber im Falle vom DEC habe ich quasi den LongString als neuen Datentyp Binary mißbraucht um auch binäre Daten damit zu speichern. Das hat, wenn man nur mit Delphi Datentypen arbeitet enorme Vorteile. Man hat einen Stringkompatiblen binären Datentyp der 1 zu 1 zuweisungskompatibel ist, man hat Autallokation, Copy on Write Demand und eben Garbarge Collection über die Delphi interne Refernezzählung dieser Datentypen. Deshalb habe ich mich für LongStrings statt dynamsichem Array of Byte entschieden. |
Re: [DEC] WideString ver/entschlüsseln
Naja ;) Aber ich habe ja nie ein #0 im Widestring?!
MfG xZise |
Re: [DEC] WideString ver/entschlüsseln
doch natürlich hast du das. Wenn du einen WideString als Speicherauszug betrachtest und der WideString enthält einen Ansi-compatiblen String dann wird jedes 2. Byte ein #0 sein. Also exakt so wie das was deine MessageBoxW() anzeigt. Nur das eben die MessageBoxW() eine WideString MessageBoxA() Variante ist und das ohne diese #0 Zeichen darstellen muß !!
Gruß Hagen |
Re: [DEC] WideString ver/entschlüsseln
Liste der Anhänge anzeigen (Anzahl: 1)
Aber wenn ich einen WideString im Debugger beobachte hat es keine #0 im String ?!
Oder ist dieser WideString dann kein Widestring? MfG xZise [edit=1]Ich habe es geradeeben getestet: TTntEdit (namens e) auf dem Formular, und dann folgende Methode:
Delphi-Quellcode:
1. Showmessage gibt den WideString korrekt an.
procedure TForm1.FormClick(Sender: TObject);
var t : WideString; begin t := e.Text; Showmessage(t); ShowMessage(t[2]); end; 2. Showmessage gibt das 2. Zeichen im WideString an (==> es ist kein #0 sondern das "dritte" Zeichen!) Ein Beispiel: WideString: "Hallo Welt" t = "Hallo Welt" (auch im Debugger) t[2] = "a" (und nicht wie zu erwarten #0)[/edit] [edit=2]Ich habe mal ein Bild von einen Echten Widestring! Keine #0 wie sie nach der entschlüsselung auftraten[/edit] |
Re: [DEC] WideString ver/entschlüsseln
Zitat:
Zitat:
Der indizierte Zeichenzugriff weiß doch um die Datenorganisation. Und wenn du WideString[] schreibst, dann gibst du das Zeichen an, auf das du zugreifen willst. Bei einem AnsiString[] ist es dann ein AnsiChar und der ist 8 Byte groß. Bei WideString[] ist es ein WideChar und der ist zwei Byte groß.
Delphi-Quellcode:
procedure TForm1.FormClick(Sender: TObject);
var t : WideString; lPtr: PByte; begin t := e.Text; lPtr := @t[0]; Showmessage(inttostr(lptr^) + ' ' + Chr(lPtr^)); inc(lptr); Showmessage(inttostr(lptr^) + ' ' + Chr(lPtr^)); inc(lptr); Showmessage(inttostr(lptr^) + ' ' + Chr(lPtr^)); // alternativ: ShowMessage(format('high %d low %d', [Hi(t[2]), Lo(t[2])])); // wenn er WideChar nicht bei Hi() und Lo() akzeptiert, dann caste auf Word... end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz