Einzelnen Beitrag anzeigen

Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#1

Sichere Verschlüsselung von Dateien mit dem DEC 5.1

  Alt 4. Apr 2006, 11:34
Dieser Code befindet sich auch im DEC-Archiv, doch hier ist er auch gut aufgehoben, da es sich um eine schöne Demonstration der Verschlüsselung von Dateien mithile des DEC handelt. Das DEC 5.1 ist nicht 100% kompatibel zum DEC 5.0, da der Code komplett überarbeitet wurde, darum im Folgenden der Code. Hagen hat dieses Beispiel hier ins Forum gestellt. Diese Demo ist nach der Installation des DEC unter \DEC\D_\DECTest\DECTest.dpr zu finden:

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.
  Mit Zitat antworten Zitat