|
Registriert seit: 30. Okt 2004 475 Beiträge Delphi 12 Athens |
#1
MemIniCrypt: Vollverschlüsseltes Arbeiten mit ini-Dateien - Kommentare erwünscht!![]()
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
![]()
Die Unit und die Testdatei befinden sich im Anhang.
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.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
Geändert von CodeX (17. Jan 2011 um 23:50 Uhr) |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |