Thema: Delphi DEC 5.1 kein "Initkey"

Einzelnen Beitrag anzeigen

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, 07: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