Delphi-Version: XE
MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Liste der Anhänge anzeigen (Anzahl: 3)
Auf der Suche nach einer Möglichkeit, die ini mit allen Einstellungen vollständig zu verschlüsseln, habe ich leider keine ideale Lösung gefunden. Alles was ich ausprobiert habe, war entweder nicht vollständig nutzbar, nicht Unicode-kompatibel, konnte die Verschlüsselung nicht deaktivieren oder erlaubte keinen mehrfachen Zugriff auf eine ini (z.B. Prozeduraufruf, der auf die ini zugreift, während sie außerhalb bereits bearbeitet wird). Ich habe mich deshalb daran gemacht, eine eigene Lösung zu entwickeln. Herausgekommen ist die Unit MemIniCrypt. Um diese verwenden zu können wird allerdings noch das freie DCPcrypt v2 benötigt. Die Unit unterstützt damit gleichzeitig auch alle Verschlüsselungsmethoden, die dort vorhanden sind. In meiner Implementierung nehme ich RC4, weil das nach meinen Tests am schnellsten arbeitete.
Die Unit und die Testdatei befinden sich im Anhang. http://www.delphipraxis.net/attachme...1&d=1295289138
Delphi-Quellcode:
// MemIniCrypt
// allows working with fully encrypted ini files // // By CodeX, v1.0, 2011-01-17 // // Features: // - Allows all encryption methods available in DCPcrypt (by default RC4) // - Fully Unicode (UTF8) compatible // - Use with or without encryption // - Allows optional shared/nested ini access (Consistent=true) or as Xzibit would say: // "Sup Dawg, we heard you like shared ini access, so we put an extra UpdateFile // into MemIniCrypt, so you can access the ini while you access the ini." ;) // // Additional functions compared to TMemIniFile: // public Encrypt, Decrypt, IsEncrypted // global IsCorrectPassword, IsIniStructure // // Requires a Unicode version of Delphi // ANSI versions (older than 2009) probably won't work correctly, but were not tested // // Requires DCPcrypt v2 // http://www.cityinthesky.co.uk/cryptography.html // Inspired by RCmxIni // http://www.delphipraxis.net/303502-post2.html unit MemIniCrypt; interface uses Classes, sysUtils, IniFiles, DCPRC4, DCPSHA1; type TMemIniCrypt = class(TMemIniFile) private FFileName: String; FPassword: String; FEncrypted: Boolean; FConsistent: Boolean; procedure LoadValues; protected public constructor Create(const FileName, Password: String; Consistent: Boolean = true); procedure WriteString(const Section, Ident, Value: String); procedure UpdateFile; override; procedure Rename(const FileName: String; Reload: Boolean); procedure EraseSection(const Section: String); procedure DeleteKey(const Section, Ident: String); procedure SetStrings(List: TStrings; ConsistentAware: Boolean = true); destructor Destroy; override; function Encrypt(Password: String): Boolean; function Decrypt: Boolean; end; function MICIsCorrectPassword(const Filename, Password: String): Boolean; function MICIsIniStructure(var List: TStringList): Boolean; function MICIsEncrypted(const Filename: String): Boolean; implementation constructor TMemIniCrypt.Create(const FileName, Password: String; Consistent: Boolean = true); var bEncrypted : Boolean; begin FFileName := FileName; FPassword := Password; FEncrypted := Password <> ''; FConsistent := Consistent; //allows shared/nested access, but is significantly slower bEncrypted := MICIsEncrypted(FileName); if (not bEncrypted) and (FPassword <> '') then Encrypt(FPassword) else if bEncrypted and (FPassword = '') then begin // ToDo: How to handle missing passwords for encrypted files // (or what to do if PW is not suitable for that ini?) // Attention! Using a wrong PW or no encryption (blank PW) // will currently erase all existing information! end; if FEncrypted then begin // Clean instancing without any values inherited Create(''); //inherited Create(FFileName); end else begin inherited Create(FFileName, TEncoding.UTF8); Encoding := TEncoding.UTF8; end; // Custom LoadValues LoadValues; end; destructor TMemIniCrypt.Destroy; begin if not FConsistent then //Only save to file if not already done UpdateFile; FPassword := ''; FFilename := ''; inherited; end; procedure TMemIniCrypt.WriteString(const Section, Ident, Value: String); begin inherited; // Save to file after each change to allow shared/nested ini access if FConsistent then UpdateFile; end; procedure TMemIniCrypt.EraseSection(const Section: String); begin inherited; if FConsistent then UpdateFile; end; procedure TMemIniCrypt.DeleteKey(const Section, Ident: String); begin inherited; if FConsistent then UpdateFile; end; procedure TMemIniCrypt.SetStrings(List: TStrings; ConsistentAware: Boolean = true); begin inherited SetStrings(List); // ConsistantAware is required to not update the file when used by LoadValues if FConsistent and ConsistentAware then UpdateFile; end; procedure TMemIniCrypt.Rename(const FileName: String; Reload: Boolean); begin FFileName := FileName; if Reload then LoadValues; end; procedure TMemIniCrypt.LoadValues; var List: TStringList; Cipher: TDCP_RC4; fsIn: TFileStream; fsOut: TMemoryStream; begin if not FEncrypted then inherited else begin if (FFileName <> '') and FileExists(FFileName) then begin List := TStringList.Create; Cipher := TDCP_RC4.Create(nil); Cipher.InitStr(FPassword, TDCP_SHA1); fsIn := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone); fsOut := TMemoryStream.Create(); try fsIn.Seek(0, soFromBeginning); Cipher.DecryptStream(fsIn, fsOut, fsIn.Size); fsOut.Seek(0, soFromBeginning); List.LoadFromStream(fsOut, TEncoding.UTF8); SetStrings(List, false); finally List.Free; fsIn.Free; fsOut.Free; Cipher.Burn; Cipher.Free; end; end else Clear; end; end; procedure TMemIniCrypt.UpdateFile; var List: TStringList; Cipher: TDCP_RC4; fsIn: TMemoryStream; fsOut: TFileStream; begin if not FEncrypted then inherited else begin List := TStringList.Create; Cipher := TDCP_RC4.Create(nil); fsOut := TFileStream.Create(FFileName, fmCreate); fsIn := TMemoryStream.Create; try Cipher.InitStr(FPassword, TDCP_SHA1); GetStrings(List); List.SaveToStream(fsIn, TEncoding.UTF8); fsIn.Seek(Length(TEncoding.UTF8.GetPreamble), soFromBeginning); Cipher.EncryptStream(fsIn, fsOut, fsIn.Size - Length(TEncoding.UTF8.GetPreamble)); finally List.Free; fsIn.Free; fsOut.Free; Cipher.Burn; Cipher.Free; end; end; end; function TMemIniCrypt.Encrypt(Password: String): Boolean; var Cipher: TDCP_RC4; fsIn: TFileStream; fsOut: TMemoryStream; begin Result := false; if length(Password) = 0 then Exit; if not((FFileName <> '') and FileExists(FFileName)) then Exit; if MICIsEncrypted(FFileName) then Exit; Cipher := TDCP_RC4.Create(nil); fsOut := TMemoryStream.Create; try Cipher.InitStr(FPassword, TDCP_SHA1); fsIn := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone); try fsIn.Seek(0, soFromBeginning); Cipher.EncryptStream(fsIn, fsOut, fsIn.Size); finally fsIn.Free; end; fsOut.Seek(0, soFromBeginning); fsOut.SaveToFile(FFileName); FPassword := Password; FEncrypted := true; Result := true; finally Cipher.Burn; Cipher.Free; fsOut.Free; end; end; function TMemIniCrypt.Decrypt: Boolean; var Cipher: TDCP_RC4; fsIn: TFileStream; fsOut: TMemoryStream; List: TStringList; i: Integer; begin Result := false; if not((FFileName <> '') and FileExists(FFileName)) then Exit; if not MICIsEncrypted(FFileName) then Exit; Cipher := TDCP_RC4.Create(nil); fsOut := TMemoryStream.Create; try Cipher.InitStr(FPassword, TDCP_SHA1); fsIn := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone); try fsIn.Seek(0, soFromBeginning); Cipher.DecryptStream(fsIn, fsOut, fsIn.Size); finally fsIn.Free; end; List := TStringList.Create; try fsOut.Seek(0, soFromBeginning); List.LoadFromStream(fsOut); // Only save if the file was encrypted correctly if MICIsIniStructure(List) then fsOut.SaveToFile(FFileName); finally List.Free; end; FEncrypted := false; Result := true; finally Cipher.Burn; Cipher.Free; fsOut.Free; end; end; function MICIsEncrypted(const Filename: String): Boolean; var fs: TFileStream; List: TStringList; begin Result := false; if not((Filename <> '') and FileExists(Filename)) then Exit; List := TStringList.Create; try fs := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); try fs.Seek(0, soFromBeginning); List.LoadFromStream(fs); Result := not MICIsIniStructure(List); finally fs.Free; end; finally List.Free; end; end; function MICIsCorrectPassword(const Filename, Password: String): Boolean; var List: TStringList; Cipher: TDCP_RC4; fsIn: TFileStream; fsOut: TMemoryStream; begin Result := false; if not((Filename <> '') and FileExists(Filename)) then Exit; List := TStringList.Create; Cipher := TDCP_RC4.Create(nil); fsIn := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); fsOut := TMemoryStream.Create(); try fsIn.Seek(0, soFromBeginning); Cipher.InitStr(Password, TDCP_SHA1); Cipher.DecryptStream(fsIn, fsOut, fsIn.Size); fsOut.Seek(0, soFromBeginning); List.LoadFromStream(fsOut); Result := MICIsIniStructure(List); finally List.Free; fsIn.Free; fsOut.Free; Cipher.Burn; Cipher.Free; end; end; function MICIsIniStructure(var List: TStringList): Boolean; var i: Integer; begin if List.Count > 0 then begin Result := false; for i := 0 to List.Count - 1 do begin if copy(List[i], 0, 1) + copy(List[i], Length(List[i]), 1) = '[]' then begin Result := true; Break; end; end; end; end; end. |
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Zitat:
Hab es aber mal wie gewünscht korrigiert |
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Du weißt aber schon, daß Stromchiffren mit konstantem Passwort ohne Initialisierungsvektor brutal unsicher sind? Und Du weißt, daß das DCPCrypt-RC4 buggy ist?
Wenn Du kein Salz oder IV hast, solltest Du auf keinen Fall eine Stromchiffre verwenden oder eine Blockcipher in den Modi CTR, OFB, ECB. |
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Zitat:
Ganz generell ist mein Szenario so, dass ein Administrator das Programm konfigurieren kann und diverse Nutzer dies anschließend verwenden sollen, ohne an den Einstellungen herumzuspielen. Deswegen soll die ini nicht im Klartext vorliegen. Dafür wird das Passwort so oder so in das Programm hardcodiert. Wir sprechen also keineswegs von Top-Sicherheit. Damit die ersten verschlüsselten Abschnitte aber nicht immer gleich aussehen, wäre ein bisschen Salz dennoch hilfreich, wo ich mir aber eben wie beschrieben nicht sicher bin, wie das am besten zu implementieren ist. Wenn jemand einen Vorschlag hat, nehme ich diesen sehr gerne mit auf. Zitat:
|
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Im Forum liegt irgendwo ein RCx (von Hagen Reddmann / negaH) rum, in welchem einige Problemchen von RC4 behoben wurden.
|
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Zitat:
Zitat:
@himitsu: Das löst doch das Problem hier überhaupt nicht und kann es auch gar nicht: Der Schüsselstrom ist doch immer der gleiche, auch ein "OTP" ist in dieser Situation unsicher (weil es eigentlich ein "MTP" ist). |
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Wenn er das Passwort eh in der EXE mit speichert, muß es garnicht 100% sicher sein, wie hier schon jemand angemerkt hatte. :angle:
|
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Zitat:
Zitat:
|
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Zitat:
|
AW: MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!
Darum hatte Hagen auch in RCx einige Änderungen einfließen lassen.
http://www.delphipraxis.net/140859-r...tml#post955578 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:05 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz