ankhmorpork
Goto Top

Free Pascal Compiler - Stream read error

Hallo Alle und Moinsen

System:
Windows 7, x64
Free Pascal Compiler 3.0.4
Lazarus IDE 1.8.4


In der Hoffnung, hier noch einen weisen Pascal-Coder zu finden:

Ich habe ein kleines Konsolen-Programm geschrieben, das kurze Texte entgegen nimmt, verschlüsselt (BlowFish) und in eine Datei schreibt. Zudem kann der Datei-Inhalt zurückgelesen, entschlüsselt und in der Konsole angezeigt werden.
Zum Speichern/Laden nutze ich Streams (TStringStream).

Die Verschlüsselung funktioniert perfekt.
Die Entschlüsselung aber nur, wenn der String exakt 4 Zeichen lang ist. Sonst schmeißt es folgenden Fehler:
Project crypt hat Exception-Klasse "EReadError" ausgelöst mit der Meldung:
Stream read error
Bei Adresse 410EE5

Mein erster Gedanke war ein Zeichensatz-Problem beim Übergang Console/Stream. Aber dann sollten mMn auch die 4-Zeichen-Strings denselben Fehler schmeißen - tun sie aber nicht. Ich habe eine Reihe von 4-Zeichen-Kombinationen durchgespielt - werden korrekt ver-/entschlüsselt.

Habe mittlerweile dutzende von Artikeln gelesen, Foren durchstöbert und Zeichensatz-Umwandlungen probiert, aber keine Erleuchtung zu vermelden.

Am BlowFish-Algorithmus liegt es auch nicht, der funktioniert perfekt (habe ich mit einer kleinen Test-Routine nachvollziehen können). Das explizite Setzen der CodePage in der Console bringt ebenfalls nix. Ich bin schlussendlich auf die Schnappsidee gekommen, die ASCII/ANSI-Codes der Chiffre in die Datei zu schreiben - ooch nöscht.

Mein Schädel stößt bereits kleine Rauchwolken aus ... ich hoffe, die Krankenkasse übernimmt das (btw: bitte keine anzüglichen Wortspiele mit dem Crypto-Algorithmus!). face-wink

Kennt einer von euch da draußen an den Geräten dieses Phänomen? Kann es mir jemand erklären? Hat jemand eine Lösung / einen Lösungsansatz?


Gruß und schöne Adzwenzzeit euch allen

Ankh


Hier noch der Quelltext:
Program crypt;
{$mode objfpc}{$H+}

uses
  Classes, Crt, SysUtils, BlowFish;

const TheFile: String = 'CryptFile.txt';  

var
  EncodeBlowFishStream: TBlowFishEncryptStream;
  DecodeBlowFishStream: TBlowFishDeCryptStream;
  EncodeStringStream,DeCodeStringStream: TStringStream;
  EncodeString,DecodedString,key,value: String;
  Choice: Char;

Procedure Encrypt;
Begin
     EncodeStringStream := TStringStream.Create('');  
     EncodeBlowFishStream := TBlowFishEncryptStream.Create(key,EncodeStringStream);
     EncodeBlowFishStream.WriteAnsiString(value);
     EncodeString := EncodeStringStream.DataString;
     EncodeBlowFishStream.Free;
     EncodeStringStream.Free;
End;

Procedure Decrypt;
Begin
     DeCodeStringStream := TStringStream.Create(value);
     DecodeBlowFishStream := TBlowFishDeCryptStream.Create(key,DeCodeStringStream);
     DecodedString := DecodeBlowFishStream.ReadAnsiString;
     DecodeBlowFishStream.Free;
     DeCodeStringStream.Free;
End;

Function ReadFile(File2Read:String):String;
Var  String2Read: TstringList;
Begin
     Value:='';  
     String2Read := TStringList.Create;
     Try
        String2Read.LoadFromFile(File2Read);
        value:=String2Read;
     Finally
         String2Read.Free;
     End;
End;

Function WriteFile(File2Write:String):String;
Var String2Write: TStringList;
Begin
     String2Write := TStringList.Create;
     Try
        String2Write.Add(EncodeString);
        String2Write.SaveToFile(File2Write);
     Finally
        String2Write.Free;
        EncodeString:='';  
     End;
End;

Begin
  While True Do
  Begin
     ClrScr;
     TextColor(LightGreen);
     Write('Encrypt = 1 | Decrypt = 2 | Exit = 3 ... Your choice: ');  
     Choice := ReadKey;
     WriteLn;
     If Choice='3' Then  
        Halt(0);

     Write('Key: ');  
     ReadLn(key);

     Case Choice of
      '1': Begin  
                Write('Text: ');  
                ReadLn(value);
                Encrypt;
                WriteLn('Encrypted: ' + EncodeString);  
                WriteLn('Decrypted: ' + value);  
                WriteFile(TheFile);
           End;
      '2': Begin  
                ReadFile(TheFile);
                Decrypt;
                WriteLn('Encrypted: ' + value);  
                writeLn('Decrypted: ' + DecodedString);  
           End;

     End; //Case
     WriteLn;
     TextColor(white);
     Write('Press ENTER to continue...');  
     ReadLn;
  End; //While
End.

Content-Key: 394842

Url: https://administrator.de/contentid/394842

Ausgedruckt am: 28.03.2024 um 09:03 Uhr

Mitglied: 137846
137846 06.12.2018 aktualisiert um 10:12:59 Uhr
Goto Top
Moin.
Wo liegt die zu lesende Datei? Auf einem Netzlaufwerk?

Gruß A.
Mitglied: AnkhMorpork
AnkhMorpork 06.12.2018 um 10:26:36 Uhr
Goto Top
@137846
Nein, lokale Festplatte
Mitglied: 137846
137846 06.12.2018 aktualisiert um 12:22:56 Uhr
Goto Top
OK, ich bau die Build-Umgebung nachher mal in einer VM nach und gebe Rückmeldung was dein Code dort meldet.
Mitglied: Friemler
Friemler 06.12.2018 aktualisiert um 21:56:59 Uhr
Goto Top
'n Abend Ankh,

ich bin Delphi-Entwickler und kenne deshalb die Details der FPC RTL nicht. Die Doku von ReadAnsiString sagt jedoch:

The Ansistring should be stored as 4 bytes (a DWord) representing the length of the string, and then the string value itself. The WriteAnsiString function writes an ansistring in such a format.

Das mit den 4 Bytes kommt mir schonmal verdächtig vor. Was passiert, wenn Du die Prozedur Decrypt folgendermaßen umschreibst:
Procedure Decrypt;
var
    TmpStream: TStringStream;
Begin
    DeCodeStringStream := TStringStream.Create(value);
    DecodeBlowFishStream := TBlowFishDeCryptStream.Create(key,DeCodeStringStream);
    TmpStream := TStringStream.Create('');  
    TmpStream.CopyFrom(DecodeBlowFishStream, DecodeBlowFishStream.Size);
    DecodedString := TmpStream.DataString;
    TmpStream.Free;
    DecodeBlowFishStream.Free;
    DeCodeStringStream.Free;
End;

Grüße
Friemler
Mitglied: AnkhMorpork
AnkhMorpork 07.12.2018 um 07:26:29 Uhr
Goto Top
Moin Friemler,

schön von dir zu "hören".

Es schmeißt wieder Fehler. Diesmal:
errmsg

In der FPC-Version 3.0+ sollte eigentlich alles UTF8 kodiert sein. Ist aber auch nur graue Theorie.

Grüße zurück

Ankh
Mitglied: Friemler
Friemler 07.12.2018 um 09:04:44 Uhr
Goto Top
Moin Ankh,

die Länge des BlowFish-Streams wird intern anscheinend durch eine Suchoperation bestimmt. Kann die Längenangabe (Parameter 2) der CopyFrom-Methode wie in Delphi auf 0 gesetzt werden, um den gesamten Stream zu kopieren?

Muss der String, damit er entschlüsselt werden kann, eigentlich genau 4 Bytes lang sein oder muss er mindestens 4 Byte lang sein? Hintergrund: Du schreibst das "eigentlich alles UTF8 kodiert sein" soll. Die Byte Order Mark (BOM) von UTF-8 ist 3 Bytes lang.

Grüße
Friemler
Mitglied: AnkhMorpork
AnkhMorpork 07.12.2018 um 09:31:52 Uhr
Goto Top
@Friemler

Die Längenangabe der CopyFrom-Methode kann auf 0 gesetzt werden, aber dann kommt Murks raus:

bild1

bild2

Der String muss exakt 4 Byte lang sein. Alle anderen Längen schmeißen den String read error.

Notepad++ sagt übrigens, dass die Datei Ansi-kodiert ist ... ?

Ich habe das Ganze auch mal unter Linux (openSUSE Leap 42.3) compiliert - selbes Fehlerbild. Das war sicher auch zu erwarten, aber ich nehme mitlerweile jeden Strohhalm mit, der nicht bei 3 auf'm Baum ist.


Danke für deine Unterstützung!

Ich wäre ja gern bei Delphi geblieben, aber die Preispolitik hat mich rausgeschmissen. Und die Zeit meiner wirklich großen Projekte ist auch vorbei. Die meisten Sachen funktionieren ja primelich, aber der Teufel steckt bekanntlich im Detail (und das habe ich hier wohl erwischt).

Glück auf

Ankh
Mitglied: Friemler
Friemler 07.12.2018 um 10:00:24 Uhr
Goto Top
Hallo Ankh

Notepad++ sagt übrigens, dass die Datei Ansi-kodiert ist ... ?

Solange keine UTF-8 Byte Order Mark und auch keine Zeichen mit einem Code größer 127 in der Datei enthalten sind, lassen sich ANSI und UTF-8 Dateien nicht unterscheiden.

Ich schätze, da musst Du mal in die RTL von FPC rein debuggen und herausfinden, durch welche Umstände der Fehler entsteht. Evtl. hast Du da einen noch nicht entdeckten Bug gefunden.

Danke für deine Unterstützung!

Gerne wieder!

Ich wäre ja gern bei Delphi geblieben, aber die Preispolitik hat mich rausgeschmissen.

Bei mir zahlt der Cheffe. face-smile


Grüße
Friemler
Mitglied: AnkhMorpork
AnkhMorpork 07.12.2018 um 10:29:56 Uhr
Goto Top
Ay Friemler,

dann werde ich mich mal auf den Weg machen und die Tiefen der RTL erkunden. Könnte ganz interesant werden.

War mal wieder angenehm, mit dir zu "arbeiten".

Alles Gute weiterhin und bleib munter.


P.S.: Frag doch bitte Cheffe, ob er mich vielleicht sponsoren möchte. face-wink
Mitglied: Friemler
Friemler 07.12.2018 um 11:02:08 Uhr
Goto Top
Hey Ankh,

Frag doch bitte Cheffe, ob er mich vielleicht sponsoren möchte.

Von der neuesten Delphi-Version 10.3 Rio gibt es eine Community Edition für umme. Damit kann man sogar kommerzielle Software entwickeln, wenn die Firma höchstens 5 Entwickler beschäftigt und höchstens $5000 Umsatz pro Jahr macht (wie davon 5 Entwickler oder auch nur einer leben sollen verraten sie nicht).

Mehr Infos und Links zum Download hier: https://www.embarcadero.com/products/delphi/starter

Grüße
Friemler
Mitglied: AnkhMorpork
AnkhMorpork 07.12.2018 um 11:34:41 Uhr
Goto Top
@Friemler

Klasse!

Vielen Dank für den Link. Werde ich gleich mal ausprobieren.

Vergiss das mit Cheffe! face-wink


Schönes WE

Ankh