Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Encrypted ZipFile (https://www.delphipraxis.net/203771-encrypted-zipfile.html)

WiPhi 21. Mär 2020 21:19

Encrypted ZipFile
 
Hallo zusammen,

ich verwende für meine Projekte u.a. die Encrypted ZipFile Quellen von Uwe Raabe zum Verschlüsseln von Zip-Dateien (an dieser Stelle besten Dank dafür!).
https://www.uweraabe.de/Blog/downloa...cryptedzipfile

Leider scheitere ich derzeit am Entpacken einer Datei von der Größe von 164.581.376 Bytes. Die verschlüsselte Zip Datei an sich ist 231.569.548 Bytes groß.

Ich erhalte beim Entpacken einen Stream Lesefehler. Die Datei wird bis zur Größe von 164.536.320 Bytes ohne Probleme entpackt. Vergleiche ich die Dateien binär, stimmen die Inhalte bis zur entsprechenden Größe überein. Nur der Rest fehlt.

Ich vermute das Problem beim ineffizenten Seek, wie auch im Blog-Post beschrieben:

Zitat:

One of the problems I encountered was the fact that the original TZipFile implementation uses Seek during decrytion to rewind the stream to a previous position. This didn’t any harm in the previous part as we used a memory stream there, but here we don’t have this luxury. Just moving the stream position will not work in this case because the decryption algorithm uses a state which is updated with each byte decrypted.

The current implementation uses a brute force approach and re-reads the whole stream from the beginning when a Seek wants to move backwards. This may be optimized for better performance in a future implementation.
https://www.uweraabe.de/Blog/2017/03...yption-part-2/
Beim Debuggen stellte ich fest, dass er bei der TDecryptStream.Seek Funktion von vorn zu suchen beginnt und das Skip dazu führt, dass er anschließend mit ReadBuffer 0 Bytes einliest, was zur Exception führt.

Delphi-Quellcode:
function TDecryptStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
var
  curPos: Int64;
  newPos: Int64;
begin
  curPos := FStream.Position;
  newPos := CurPos;
  case Origin of
    soBeginning: newPos := Offset;
    soCurrent: newPos := curPos + Offset;
    soEnd: newPos := FStreamSize + Offset;
  end;
  if newPos < curPos then begin
    ResetStream;
    result := Skip(newPos);
  end
  else begin
    result := Skip(newPos - curPos);
  end;
end;
Vielleicht hat der ein oder andere eine Idee, wie man das Problem lösen könnte. Eine Testdatei hätte ich auch zur Verfügung, aber ich denke das lässt sich auch mit der anderen größeren Datei reproduzieren.

Viele Grüße und bleibt gesund!

fux75 31. Mär 2020 11:33

AW: Encrypted ZipFile
 
Hallo WiPhi,

Ich bin auf genau das selbe Problem gestoßen. Allerdings ging es bei mir um viele kleine Dateien.

Wie du auch, vermutete ich das Problem im
Code:
Seek
des
Code:
TDecryptStream
.

Ich habe die Implementierung folgendermaßen angepasst:

Code:
function TDecryptStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
var
  curPos: Int64;
  newPos: Int64;
begin
  curPos := FStream.Position;
  newPos := CurPos;
  case Origin of
    soBeginning: newPos := Offset;
    soCurrent: newPos := curPos + Offset;
    soEnd: newPos := FStreamSize + Offset;
  end;
  if newPos < curPos then begin
//    ResetStream;
//    result := Skip(newPos);
    FStream.Position := FStreamStartPos + newPos;
    result := FStream.Position;
  end
  else begin
    result := Skip(newPos - curPos);
  end;
end;
Der Originalcode in
Code:
newPos < curPos
ist auskommentiert und durch die beiden neuen Zeilen im Block ersetzt.

Ich habe es auch mit einigen großen ca. 10MB und einer 290MB großen Datei getestet. Bei mir funktioniert der Aufruf von
Code:
aZipFile.Read(aZipFileIndex, aBytes)
mit dem Index der Datei und einem Byte Array.
Nebeneffekt ist, dass die Dekomprimierung nicht merklich langsamer wird, je mehr aus dem Zip File gelesen wird. Zumindest in dem umgeschriebenen Abschnitt wird der von Uwe Raabe erwähnte Brute Force Ansatz vermieden.

Vielleicht hilft es dir auch.
Vielen Dank auch an Uwe Raabe für die Quellen.


Gruß fux!!!

himitsu 31. Mär 2020 11:52

AW: Encrypted ZipFile
 
Ich hoffe ja die machen das im Setter von Position richtig. (sollten/müssten sie eigentlich, und da es funktioniert, scheint es so).

Das Problem ist ja, dass man die Verschlüsselung nicht rückwärts laufen lassen kann.
* Beim Sprung vorwärts kann einfach das dazwischen gelesen werden, um die Verschlüsselung fortzuführen.
* Beim Sprung zurück bleibt nur die Möglichkeit zum Anfang zu springen, alles zurückzusetzen und wieder bis zur neuen Position zu lesen, um die Verschlüssekung auf diese Stelle zu schieben.

Man könnte das jetzt noch optimieren, indem man Marker erstellen lässt, bzw. regelmäßig welche einfügt,
also an gewissen Stellen sich Position+ZustandDerVerschlüsselung speichert, womit man dann "schnell" zu diesen Positionen springen, die Verschlüsselung zurückzusetzen und dort fortfahren zu können, ohne immer wieder komplett zum Anfang zurück zu müssen.



Im Prinzip macht ResetStream+Skip ja eigentlich alles richtig ... k.A. warum es damit Probleme gibt.
Einzig, was ich mir vorstellen kann, bei über 2 GB (hab nicht nachgesehn), dass Skip nicht mit 64 Bit arbeitet und dann die falsche Position anspringt (Integerüberlauf).

WiPhi 2. Apr 2020 15:59

AW: Encrypted ZipFile
 
Zitat:

Zitat von fux75 (Beitrag 1460911)
Hallo WiPhi,

Der Originalcode in
Code:
newPos < curPos
ist auskommentiert und durch die beiden neuen Zeilen im Block ersetzt.

Genial, damit scheint es zu funktionieren! Erste Tests sehen vielversprechend aus.

Vielen Dank!

Uwe Raabe 2. Apr 2020 16:24

AW: Encrypted ZipFile
 
Zitat:

Zitat von WiPhi (Beitrag 1461097)
Genial, damit scheint es zu funktionieren! Erste Tests sehen vielversprechend aus.

Das solltest du aber nochmal genau überprüfen, denn:
Zitat:

Just moving the stream position will not work in this case because the decryption algorithm uses a state which is updated with each byte decrypted.
Allerdings ist der Code auch noch nicht für die aktuelle Delphi-Version getestet.

fux75 3. Apr 2020 07:44

AW: Encrypted ZipFile
 
Ich kann momentan auch nicht erklären, was mit dem Originalcode nicht funktioniert. Meine ersten Gedanken gingen in Richtung Integerüberlauf oder ein Problem durch 32-64 Bit Integer. Uwes Blogpost ist ursprünglich von 2017. Ich habe mehrere Stunden damit zugebracht, die vermuteten Probleme zu bestätigen. Leider war ich damit nicht erfolgreich. Der Code sollte genau so funktionieren, wie Uwe beschrieben hat.
Meine Änderung war am Ende nur noch ein Notgriff, der bislang funktioniert. Ich bin auch sicher, dass Uwes Code in 2017 mit einer früheren Delphi Version funktioniert hat. Vielleicht ist der hier aufgetretene Fehler nur eine Folge eines anderen Problems in TZipFile in der aktuellen Delphi Version. Was in zukünftigen Versionen passiert sollte man genau im Auge haben.

Viele Grüße an alle - und bleibt gesund!


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:54 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