Einzelnen Beitrag anzeigen

daniel-volk

Registriert seit: 16. Jul 2003
170 Beiträge
 
Delphi 6 Enterprise
 
#91

Re: Dateien verschlüsseln - aber wie?

  Alt 13. Okt 2003, 20:58
Hello world!

Ich hab ja jetzt mein Programm so weit, dass es schon ganz vernünftig läuft.
Aber eine Sache gefällt mir noch nicht:
Bis 10MB ist das alles überhaupt kein Problem, 20MB dauern etwas - gehn aber immer noch schnell - und 40MB dauern ewig. Das Verschlüsseln geht dabei immer noch, aber das Entschlüsseln ist ein Katastrophe! Das dauert viel zu lange!
40MB dauern abgesehen davon mindesten 10mal so lange wie 10MB. Und das wird wohl daran liegen, dass ich mit dem MemoryStream arbeite und der den Arbeitsspeicher dann zu sehr ausfüllt. Und wenn Win dann erst anfängt in die Auslagerungsdatei zu schreiben, dann hab ich eh verloren...

Der aktuelle Code sieht jetzt so aus:
Delphi-Quellcode:
// Datei entschlüsseln
function TFrmCipher.DecodeFile(Input, Output, Passwd: String): Boolean;
var
  SrcStream, DestStream: TStreamProgressAdapter;
  TempStream: TMemoryStream;
  NewHeader, OldHeader: TFileHeader;
begin
  Button13.Show;
  ProgressBar1.Show;
  LbProgress.Show;
  FrmCipher.Refresh;
  result := False;
  SrcStream := TStreamProgressAdapter.Create(TFileStream.Create(Input, fmOpenRead or fmShareDenyNone),Handle);
  if Assigned(SrcStream) then
  begin
    try
      DestStream := TStreamProgressAdapter.Create(TFileStream.Create(Output, fmCreate),Handle);
      if Assigned(DestStream) then
      begin
        try
        TempStream := TMemoryStream.Create;
        if Assigned(TempStream) then
        begin
          try
            LbProgress.Caption := 'Die Datei wird entschlüsselt... (1/3)';
            FrmCipher.Refresh;
            with DefCipherClass.Create('', nil) do
              begin
                try
                  Mode := DefCipherMode;
                  HashClass := DefHashClass;
                  InitKey(Passwd, nil);
                  // Zuerst wird SrcStream Decodiert und in TempStream geschrieben
                  DecodeStream(SrcStream, TempStream, SrcStream.Size);
                  // jetzt befindet sich am Anfang von TempStream der FileHeader
                finally
                  Free;
                end;
              end;
              TempStream.Seek(0,sofrombeginning);
              // Der FileHeader wird gelesen
              TempStream.ReadBuffer(OldHeader,SizeOf(TFileHeader));
              DestStream.FMax := TempStream.Size - TempStream.Position;
              LbProgress.Caption := 'Die entschlüsselte Datei wird aus dem Arbeitsspeicher in die Zieldatei geschrieben... (2/3)';
              FrmCipher.Refresh;
              DestStream.CopyFrom(TempStream,TempStream.Size-TempStream.Position);
              DestStream.Seek(0,sofrombeginning);
              LbProgress.Caption := 'Der Hash-Wert der entschlüsselten Datei wird berechnet... (3/3)';
              FrmCipher.Refresh;
              with DefHashClass.Create(nil) do
              begin
                try
                  NewHeader.HashString := CalcStream(DestStream,DestStream.Size,nil,DefFileStringFormat);
                finally
                  Free;
                end;
              end;
              finally
                FreeAndNil(TempStream);
              end;
        end else
        begin
          RaiseLastOSError();
          exit;
        end;
      finally
        FreeAndNil(DestStream);
      end;
    end else
    begin
      RaiseLastOSError();
      exit;
    end;
  finally
    FreeAndNil(SrcStream);
  end;
  end else
  begin
    RaiseLastOSError();
    exit;
  end;
  If NewHeader.HashString = OldHeader.HashString then
  result := true else
  result := false;
  LbProgress.Caption := '';
  LbProgress.Hide;
  ProgressBar1.Hide;
  Button13.Hide;
end;

// Datei verschlüsseln
function TFrmCipher.EncodeFile(Input, Output, Passwd: String): Boolean;
var
  SrcStream: TStreamProgressAdapter;
  DestStream: TFileStream;
  TempStream: TStreamProgressAdapter;
  FileHeader : TFileHeader;
begin
  Button13.Show;
  ProgressBar1.Show;
  LbProgress.Show;
  FrmCipher.Refresh;
  result := False;
  SrcStream := TStreamProgressAdapter.Create(TFileStream.Create(Input, fmOpenRead or fmShareDenyNone),Handle);
  if Assigned(SrcStream) then
  begin
    try
      DestStream := TFileStream.Create(Output, fmCreate);
      if Assigned(DestStream) then
      begin
        try
          TempStream := TStreamProgressAdapter.Create(TMemoryStream.Create, Handle);
          if Assigned(TempStream) then
          begin
          try
          SrcStream.Seek(0,sofrombeginning);
          LbProgress.Caption := 'Der Original-Hash-Wert wird berechnet... (1/3)';
          FrmCipher.Refresh;;
          with DefHashClass.Create(nil) do
          begin
            try
              FileHeader.HashString := CalcStream(SrcStream,SrcStream.Size,nil,DefFileStringFormat);
            finally
              Free;
            end;
          end;
          TempStream.FMax := SizeOf(TFileHeader);
          TempStream.Seek(0,sofrombeginning);
          TempStream.Write(FileHeader, sizeof(TFileHeader));
          LbProgress.Caption := 'Die Originaldatei wird in den Arbeitsspeicher kopiert... (2/3)';
          FrmCipher.Refresh;
          SrcStream.Seek(0,sofrombeginning);
          TempStream.FMax := TempStream.Size + SrcStream.Size;
          TempStream.CopyFrom(SrcStream,SrcStream.Size);
          TempStream.Seek(0,sofrombeginning);
          DestStream.Seek(0,sofrombeginning);
          LbProgress.Caption := 'Die Datei wird verschlüsselt... (3/3)';
          FrmCipher.Update;
          with DefCipherClass.Create('', nil) do
          begin
            try
              Mode := DefCipherMode;
              HashClass := DefHashClass;
              InitKey(Passwd, nil);
              EncodeStream(TempStream, DestStream, TempStream.Size);
            finally
              Free;
            end;
          end;
        finally
          FreeAndNil(TempStream);
        end;
      end
      else
      begin
        RaiseLastOSError();
        exit;
      end;
        finally
          FreeAndNil(DestStream);
        end;
      end
      else
      begin
        RaiseLastOSError();
        exit;
      end;
    finally
      FreeAndNil(SrcStream);
    end;
  end
  else
  begin
    RaiseLastOSError();
    exit;
  end;
  result := True;
  ProgressBar1.Hide;
  LbProgress.Caption := '';
  LbProgress.Hide;
  Button13.Hide;
end;
Wie ihr sehen könnt, gehe ich bei der Verschlüsselung nach folgender "Formel" vor:
Ziel := AES-Verschlüsselung([Header mit Hash-Wert]+Originaldatei);
(Ich hoffe mal das ist so verständlich.)

Das Problem bei der Geschichte ist halt nur, dass ich den Header nur in einem Zug mitverschlüsseln kann, wenn er in einem Stream mit der Datei steht. Ansonsten gibt das zwischendurch einen Schnitt, der dann wiederum bewirkt, dass die Verschlüsselung hinter dem Header neu beginnt. Und dann ist der Random-Effekt, den ich durch die Kombination von Header und Cipher Block Changing erziele, hin.

Noch schlimmer wird die Sache beim Entschlüsseln, weil ich da dann das Problem bekomme, dass ich den Header erst nach dem Entschlüsseln entfernen kann, was aber auch aus Sicherheitsgründen so sein muss.

Also hier mein genaues Ziel:
1) Die Bearbeitungsgeschwindigkeit soll maximiert werden und die Speicherauslastung gleichzeitig minimiert.
2) Es darf - genau wie jetzt - nur einmal eine Ausgabedatei geschrieben werden. Die Quelldatei darf nicht verändert werden.
3) Die Sicherheit darf nicht leiden. Soll heißen: Dateien, die mit dem Algo oben verschlüsselt wurden, sollen mit dem neuen Algo wieder zu entschlüsseln sein! Das stellt dann sicher, dass es auch wirklich keinen Schnitt zwischen Hash und Datei gibt!
4) Kurz gesagt: Es soll alles so sein wie oben nur eben optimiert.

Ich hab schon einige Sachen in Gedanken versucht, bin dann aber immer wieder auf irgendwelche Probleme gestoßen. Vielleicht fällt einem von euch ja der Stein der Waisen ein.

Ciao,
Daniel.
  Mit Zitat antworten Zitat