AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DEC 5.1 kein "Initkey"

Ein Thema von jus · begonnen am 3. Apr 2006 · letzter Beitrag vom 3. Apr 2006
Antwort Antwort
jus

Registriert seit: 22. Jan 2005
343 Beiträge
 
Delphi 2007 Professional
 
#1

DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 01:51
Hallo!

Ich möchte zunächst ein einfaches Verschlüsselungsprogramm für Dateien mit Hilfe der DEC-Bibliothek schreiben, das über ein Passwort die Daten verschlüsselt. Nach dem Durchlesen der verschiedenen Beiträgen in diesem Forum scheint es so, dass EncodeStream/DecodeStream für meinen Vorhaben ziemlich gut geeignet ist. Das Problem ist, dass die Parameter von den alten Beiträgen beim aktuelle DEC 5_1 nicht mehr funktionieren. Leider blicke ich beim neuen DECCipher.pas nicht ganz durch.
Bitte um Hilfe!
Delphi-Quellcode:
const
  DefCipherClass: TDECCipherClass = TCipher_Rijndael;
  CipherMode = cmCBCx; <----------Frage 2.


procedure TForm1.Button3Click(Sender: TObject);
var
  decStream: TMemoryStream;
  encStream: TMemoryStream;
begin
// if fileexists(edit1.Text);
  decStream := TMemoryStream.Create; // TStream für den Text erzeugen
  encStream := TMemoryStream.Create; // Stream für die Verschlüsselung
  try
    with DefCipherClass.Create do
    begin
      try
        Mode := CipherMode;
        InitKey('passwort', nil); //<----------- FRAGE 1.
        EncodeStream(decStream, encStream, decStream.Size);
        encStream.SaveToFile('edit2.text'); // Stream speichern
      finally
        Free;
      end;
    end;
  finally
    encStream.Free;
    decStream.Free;
  end;
end;
Nun meine Fragen:
1. Das ganze scheitert schon mal beim InitKey. Es scheint, dass InitKey nicht im DEC5_1 mehr existiert.
2. Ich habe gelesen, dass man als Standard "cmCBC" verwenden soll. Entspricht es nun im DEC 5_1 den "cmCBCx"?


jus
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#2

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 06:09
Hi,

ihr müsst auch mal in die Sourcen reinschauen. In dem Falle DECCipher.pas mal öffnen.
Vorweg: DEC 5.1. ist im Grunde eine komplette Neuentwicklung/Überarbeitung des alten DEC. Es sind neue Erkenntnisse eingeflossen und alte Designfehler im DEC sind strikt beseitigt worden. Naja, worauf ich hinaus will ist das DEC 5.x. nicht 100% kompatibel zum alten DEC sein kann !!

TDECCipher

Delphi-Quellcode:
// gibt einen Record gefüllt mit wichtigen Parametern zum Algo zurück, siehe TCipherContext
    class function Context: TCipherContext; virtual; abstract;

// initialisiert einen Cipher, Schlüsselsetup
    procedure Init(const Key; Size: Integer; const IVector; IVectorSize: Integer; IFiller: Byte = $FF); overload;
    procedure Init(const Key: Binary; const IVector: Binary = ''; IFiller: Byte = $FF); overload;

// finalisiert Cipher, nach Aufruf von .Done; befindet sich der Cipher wieder EXAKT im
// gleichen Zustand wie nach dem Aufruf von .Init()

    procedure Done;

// zerstört die internen Daten = Workingspace des Ciphers, nach einem Aufruf befindet sich der Cipher
// im gleichen Zustand wie nach .Create;
    procedure Protect; virtual;

// basis Ver-/Entschlüsselungs Methoden
    procedure Encode(const Source; var Dest; DataSize: Integer);
    procedure Decode(const Source; var Dest; DataSize: Integer);

// "in einem Rutsch" Funktionen
    function EncodeBinary(const Source: Binary; Format: TDECFormatClass = nil): Binary;
    function DecodeBinary(const Source: Binary; Format: TDECFormatClass = nil): Binary;
    procedure EncodeFile(const Source, Dest: String; const Progress: IDECProgress = nil);
    procedure DecodeFile(const Source, Dest: String; const Progress: IDECProgress = nil);
    procedure EncodeStream(const Source, Dest: TStream; const DataSize: Int64; const Progress: IDECProgress = nil);
    procedure DecodeStream(const Source, Dest: TStream; const DataSize: Int64; const Progress: IDECProgress = nil);

// aktueller Status des Ciphers, siehe TCipherState.
    property State: TCipherState
DEC 5.1. Cipher verwalten einen eigenen Status ihres internen Zustandes, dies ist neu im Vergleich zu DEC und verhindert die falsche Benutzung durch den Anwender (also DICH).

Ein Cipher wird
1.) erzeugt -> .Create() -> csNew
2.) initialisiert -> .Init() -> csInitialized
3.) arbeitet, entweder
3.1.) verschlüsselt -> .Encode() -> csEncode, oder
3.2.) entschlüsselt -> .Decode() -> csDecode, aber innerhalb einer Initialisierung nur eines von beiden
3.3.) wird automatisch ein Padding vornehmen -> csPadding, wenn die Nachricht einen Block mit <> Cipher.Context.BlockSize Bytes vorfindet und damit das weitere ver-/entschlüsseln sperren !
4.) finalisiert -> .Done() -> csDone, was dem csInit entspricht.

D.h. die neuen Cipher verwalten eine FSM die logische Fehlbenutzungen verhindern.

Nun zum .InitKey() Problem:

Diese Funktion wurde komplett entfernt weil sie eine "Protokoll"-spezifische Funktion war. Das bdeutet .Initkey() hat intern mit einem Hash Algorithmus das Passwort in einen Sessionkey umgewandelt. Die Art&Weise wie das erfolgte war nicht standardisiert, noch hatte der Anwender darauf Einflußmöglichkeiten. .InitKey() mag für Anfänger die richtige Funktion gewesen sein, aber für ein standardkonformes Verhalten der Cipher war es falsch.

Im DEC 5.1. ist nun der Anwender selber für das Postprocessing des Passwortes verantwortlich, wenn er es wünscht, und sich für eines der vielen möglichen Verfahren entschlossen hat (es gibt Dutzende).
Die einfachste Form der Initialisierung ist

Delphi-Quellcode:
with TCipher_Rijndael.Create do
try
  Mode := cmCBC8;
  Init('Passwort');
  Result := EncodeBinary('Test Nachricht', TFormat_HEX);
finally
  Free;
end;
dies verschlüsselt einen String. Da die Nachricht sehr kurz ist benutzen wir den Feedbackmodus cmCBC8, ein Cipher Block Chaining Modus der mit 8 Bit Feedback arbeitet. cmCBCx dagegen arbeitet im Cipher.Context.BlockSize * 8 Bit Feedback, d.h. auf voll Blockgröße des Ciphers. Wenn wir Rijndael betrachten so hat der eine Blockgröße von 16 Bytes, d.h. intern wird die Nachricht immer in Stücken a 16 Bytes zerlegt und dann jedes Stück durch Rijndael verschlüsselt. Der Feedback Modus verknüpft nun die vorherigen und nachfolgenden ver/entschlüsselten Blöcke miteinander. Die Art&Weise dieser Verknüpfung hängt vom Cipher.Mode ab. Bei allen cm???x Modis wird immer auf Blockgröße gearbeitet. Bei allen cm???8 Modis auf 8 Bit Grenze, sprich Byteweise. Beim Rijndael bedeutet dies das pro verschlüsseltem Byte also 1 * 16 Bytes an Blockdaten verschlüsselt werden, also pro 16 Bytes wurde 16 mal die Verschlüsselung durchgeführt. Bei cmCBCx wird pro 16 Bytes nur 1 mal verschlüsselt.
D.h. alle cm???8 Modis verschlüsseln Blocksize mal mehr als die cm???x Modis und sind dementsprechend langsammer, dafür aber sicherer besonders wenn es um sehr kurze Nachrichten geht.
cmCBCx ist kompatibel zum alten DEC -> cmCBC.

Ein besseres Keysetup würde zb. THash_???.KDFx() -> eine indexed Key Derivation Function benutzen um mit einem Salt = Zufallswert ein Passwort in ein sicheren Sessionkey für den Cipher umzuwandeln. Die Entscheidung liegt aber alleinig beim Anwender -> dir.

Der obige Vorschlag ist also die primitivste Form der Anwendung einer Verschlüsselung und schützt in keinster Weise das Passwort des Benutzers noch verhindert es bestimmte Angriffe. Dafür ist er aber in den meisten Fällen immer zu 100% kompatibel zu anderen Libraries. So bald man das sicherer machen möchte werden immer mehr Entscheidungen notwendig in der Auswahl und Anwednung bestimmter Verfahren. Damit wird es zwar sicherer aber die Kompatibilität zu anderen Libraries wird immer mehr sinken. Diese Entscheidung kann ich als Entwickler vom DEC also nicht treffen, das muß schon der Anwender selber machen.

gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#3

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 06:23
Im DECTest Projekt -> \DEC\D?\DECTest\DECTest.bpg findet sich dann auch eine Demonstration für die Verschlüsselung von Dateien.

Delphi-Quellcode:
uses DECRandom;

procedure DemoCipherFile;
// demonstriert eine sehr sichere Anwendung von Verschlüsselungen, Hashfunktionen,
// Key Derivation Functions und Zufallsdaten.


  procedure EncodeFile(const AFileName: String; const APassword: Binary;
                       ACipher: TDECCipherClass = nil; AMode: TCipherMode = cmCTSx;
                       AHash: TDECHashClass = nil);
  // Die Datei wird verschlüsselt danach überschrieben und gelöscht.
  // Die verschlüsselte Datei wurde mit einem Session Passwort verschlüsselt das mit Hilfe
  // einer KDF = Key Derivation Funktion und einem Zufallswert erzeugt wurde.
  // Der Zufallswert == Seed ist 128 Bits groß und wird in der verschlüsselten Datei gespeichert.
  // Dieser stellt sicher das es unmöglich wird das Passwort zu knacken und randomisiert zusätzlich
  // die Daten der Vershlüsselung. Am Ende der verschlüsselten Datei wird eine Prüfsumme gespeichert
  // mit Hilfe einer CMAC = Cipher Message Authentication Code.
  // Die verschlüsselte Datei enthält am Anfang zusätzlich noch Informationen zum
  // verwendeten Cipher-/Hash Algorithmus, CipherMode usw. Dies ermöglicht bei der Entschlüsselung der
  // Datei die automatische Auswahl der Algorithmen.
  // Werden für Cipher und oder Hash == nil übergeben so wird der Standard Cipher/Hash benutzt.
  // Das benutze Session Passwort hat immer Zufällige Eigenschaften, es verhält sich wie Zufallsdaten.
  // Nur derjenige der den Zufalls-Seed und APassword kennt kann die Daten korrekt entschlüsseln.
  var
    Dest: TStream;

    procedure Write(const Value; Size: Integer);
    begin
      Dest.WriteBuffer(Value, Size);
    end;

    procedure WriteByte(Value: Byte);
    begin
      Write(Value, SizeOf(Value));
    end;

    procedure WriteLong(Value: LongWord);
    begin
      Value := SwapLong(Value);
      Write(Value, SizeOf(Value));
    end;

    procedure WriteBinary(const Value: Binary);
    begin
      WriteByte(Length(Value));
      Write(Value[1], Length(Value));
    end;

  var
    Source: TStream;
    Seed: Binary;
  begin
    ACipher := ValidCipher(ACipher);
    AHash := ValidHash(AHash);

    Seed := RandomBinary(16);

    Source := TFileStream.Create(AFileName, fmOpenReadWrite);
    try
      Dest := TFileStream.Create(AFileName + '.enc', fmCreate);
      try
        with ACipher.Create do
        try
          Mode := AMode;
          Init(AHash.KDFx(APassword, Seed, Context.KeySize));

          WriteLong(Identity);
          WriteByte(Byte(Mode));
          WriteLong(AHash.Identity);
          WriteBinary(Seed);
          WriteLong(Source.Size);
          EncodeStream(Source, Dest, Source.Size);
          WriteBinary(CalcMAC);
        finally
          Free;
        end;
      finally
        Dest.Free;
      end;
      ProtectStream(Source);
    finally
      Source.Free;
    end;
    DeleteFile(AFileName);
  end;

  procedure DecodeFile(const AFileName: String; const APassword: Binary);
  // entschüssele eine Datei die vorher mit EncodeFile() verschlüsselt wurde.
  var
    Source: TStream;

    procedure Read(var Value; Size: Integer);
    begin
      Source.ReadBuffer(Value, Size);
    end;

    function ReadByte: Byte;
    begin
      Read(Result, SizeOf(Result));
    end;

    function ReadLong: LongWord;
    begin
      Read(Result, SizeOf(Result));
      Result := SwapLong(Result);
    end;

    function ReadBinary: Binary;
    begin
      SetLength(Result, ReadByte);
      Read(Result[1], Length(Result));
    end;

  var
    Dest: TStream;
  begin
    Source := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
    try
      try
        Dest := TFileStream.Create(ChangeFileExt(AFileName, ''), fmCreate);
        try
          try
            with CipherByIdentity(ReadLong).Create do
            try
              Mode := TCipherMode(ReadByte);
              Init(HashByIdentity(ReadLong).KDFx(APassword, ReadBinary, Context.KeySize));
              DecodeStream(Source, Dest, ReadLong);
              if ReadBinary <> CalcMAC then
                raise EDECException.Create('Invalid decryption');
            finally
              Free;
            end;
          except
            ProtectStream(Dest);
            raise;
          end;
        finally
          Dest.Free;
        end;
      except
        DeleteFile(ChangeFileExt(AFileName, ''));
        raise;
      end;
    finally
      Source.Free;
    end;
  end;

var
  FileName: String;
begin
  WriteLn(#13#10'File En/Decryption test');

// stelle Standard Cipher/Hash ein.
  SetDefaultCipherClass(TCipher_Rijndael);
  SetDefaultHashClass(THash_SHA1);
// Stelle die Basis-Identität der Cipher/Hash Algorithmen auf einen Anwendungsspezifischen Wert ein.
// Damit ist sichergestellt das nur Dateien die mit dieser Anwendung verschlüsselt wurden auch wieder
// entschlüselbar sind. Dei Verschlüsselungsfunktion oben speichert ja die Identity des benutzen
// Ciphers/Hashs in der verschlüsselten Datei ab. Beim Entschlüsseln mit DecodeFile() werden diese
// Identities geladen und aus den Regstrierten DECClassen geladen.
  IdentityBase := $84485225;
// alle benutzten und ladbaren Cipher/Hash müssen registriert werden.
  RegisterDECClasses([TCipher_Rijndael, THash_SHA1]);
// obige Sourcezeilen sollten normalerweise im Startup der Anwendung erfolgen.

  FileName := ChangeFileExt(ParamStr(0), '.test');
  EncodeFile(FileName, 'Password');
  DecodeFile(FileName + '.enc', 'Password');
end;

// und Anwendung eines besseren Keysetups

procedure DemoCipher(Index: Integer);
// demonstrate en/decryption with cipher Blowfish and use of a
// secure Hash based random KDF -> Key Derivation Function
var
  Seed, Encoded, Decoded: Binary;
begin
  Seed := RandomBinary(16);

  with TCipher_Blowfish.Create do
  try
    Init(THash_SHA1.KDFx('Password here', Seed, Context.KeySize));
    Encoded := EncodeBinary('Secret data here', TFormat_MIME64);
  finally
    Free;
  end;

  with TCipher_Blowfish.Create do
  try
    Init(THash_SHA1.KDFx('Password here', Seed, Context.KeySize));
    Decoded := DecodeBinary(Encoded, TFormat_MIME64);
  finally
    Free;
  end;

  WriteLn(#13#10'Demo Cipher #', Index);
  WriteLn('encoded: ', Encoded);
  WriteLn('decoded: ', Decoded);
end;

initialization
  RandomSeed; // randomize DEC's own RNG
end.
Gruß Hagen
  Mit Zitat antworten Zitat
jus

Registriert seit: 22. Jan 2005
343 Beiträge
 
Delphi 2007 Professional
 
#4

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 10:46
Wow, die Antwort ging aber schnell! Respekt!
Vielen vielen Dank Hagen, dass du dir Zeit genommen hast für mich! Ich werde das mal versuchen umzusetzen, wenn ich das geschafft habe, werde ich es hier posten, damit andere Anfänger wie ich dann ein halbwegs fertiges Kochrezept zu diesem aktuellen DEC haben.

jus
  Mit Zitat antworten Zitat
jus

Registriert seit: 22. Jan 2005
343 Beiträge
 
Delphi 2007 Professional
 
#5

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 13:10
Hier ist wie angekündigt meine Umsetzung von Hagens Code in Delphi7.

Viel Spaß!

jus

P.S.: Bitte nicht schlagen ,wenn es irgendwelche Fehler enthält.


updated:
Altes "Filecrypt.zip" wurde gelöscht. Die neue Version steht im übernächsten Beitrag von mir weiter unten.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#6

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 14:11
@jus:

die Wahl, in meiner originalen Funktion, das man nur einen Dateinamen übergeben kann hatte seinen Grund.
Durch deine Änderungen ist es nun möglich das InputFileName == OutputFilename ist. Da du dies nicht explizit abfragst arbeiten die Funktionen auf der gleichen Datei und zerstören so sich gegenseitig ihre Daten, bzw. bei entsprechendem Dateimodus wird es eine Exception geben.

Du solltest also zwingend abfragen ob InputFileName <> OutputFileName ist.
Davon abgesehen würde ich sie ASourceFileName und ADestFileName nennen.

Gruß Hagen
  Mit Zitat antworten Zitat
jus

Registriert seit: 22. Jan 2005
343 Beiträge
 
Delphi 2007 Professional
 
#7

Re: DEC 5.1 kein "Initkey"

  Alt 3. Apr 2006, 17:34
@Hagen:
Vielen Dank nochmals für den Tipp mit den doppelten Dateinamen!
Ich habe die Abfrage mit einer quick&dirty solution eingebaut. Weiters habe ich die Dateinamen nach "ASourceFileName" und "ADestFileName" unbenannt.

jus
Angehängte Dateien
Dateityp: zip filecrypt_101.zip (230,9 KB, 129x aufgerufen)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es 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

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21: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