Laden...

Client/Server Socket-Verbindung Ver- und Entschlüsselung von Files mit NetworkStream

Erstellt von Z4che vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.132 Views
Z
Z4che Themenstarter:in
2 Beiträge seit 2018
vor 5 Jahren
Client/Server Socket-Verbindung Ver- und Entschlüsselung von Files mit NetworkStream

Servus zusammen,

vorneweg: Ich bin kein Programmier-Anfänger, aber habe auch nicht den best aussehensten Code 😄
Zurzeit arbeite ich an einem kleinen Projekt, welches Dateien vom eigenen Rechner an einen Server schickt, dort sollen die Files verschlüsselt, zum Schluss an den Client zurückgeschickt und auf seiner Festplatte gespeichert werden. Die Entschlüsselung funktioniert nach dem gleichen Prinzip.
Ich habe mein Problem bisher wie folgt gelöst: Client und Server haben einen Callback/Service die über Interfaces miteinander kommunizieren. Der Client ist eine Windows-Forms-App und der Server ne simple Konsolen-App.
Momentan übergibt der Client dem Server lediglich den Pfad auf dem sich die Datei befindet, die verschlüsselt/entschlüsselt werden soll. Das möchte ich gern ändern und dem Server einen Stream übergeben. Am Besten einen NetworkStream, aber dazu weiter unten mehr warum ich diese Lösung habe, aber auch warum ich es selbstständig nicht hinbekomme.
Damit ihr euch das ein wenig besser vorstellen könnt, habe ich Code-Snippets mitgebracht. Die Standard-Methoden bzw. das was funktioniert und für meine Problemstellung irrelevant sind, habe ich rausgelassen.

Der unten stehende Code ist vom Callback des Clients:

private string pathPlain = @"", pathEncrypt = @"", pathDecrypt = @"";
        private byte[] Key, IV;
        TiService service;

private void Btn_Encrypt_Click(object sender, EventArgs e)
        {
            using (var aescsp = new AesCryptoServiceProvider())
            {
                Key = aescsp.Key;
                IV = aescsp.IV;
                service.Enc(pathPlain, Key, IV, pathEncrypt);
            }
         }

        private void Btn_Decrypt_Click(object sender, EventArgs e)
        {
            using (var aescsp = new AesCryptoServiceProvider())
            {
                Key = aescsp.Key;
                IV = aescsp.IV;
                service.Dec(pathEncrypt, Key, IV, pathDecrypt);
            }
        }

Der nachfolgende Code ist vom Service des Servers:


        public void Enc(string pathPlain, byte[] Key, byte[] IV, string pathEncrypt)
        {
            using (var rijAlg = new AesCryptoServiceProvider())
            {
                //rijAlg.Padding = PaddingMode.Zeros;
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                Transform(pathPlain, pathEncrypt, encryptor);
            }
        }

        public void Dec(string pathEncrypt, byte[] Key, byte[] IV, string pathDecrypt)
        {
            using (var rijAlg = new AesCryptoServiceProvider())
            {
                //rijAlg.Padding = PaddingMode.Zeros;
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                Transform(pathEncrypt, pathDecrypt, decryptor);
            }
        }

        public void Transform(string source, string target, ICryptoTransform transf)
        {
            var bufferSize = 65536;
            var buffer = new byte[bufferSize];


            using (var sourceStream = new FileStream(source, FileMode.Open))
            {
                using (var targetStream = new FileStream(target, FileMode.OpenOrCreate))
                {
                    using (CryptoStream cs = new CryptoStream(targetStream, transf, CryptoStreamMode.Write))
                    {
                        var bytesRead = 0;
                        do
                        {
                            bytesRead = sourceStream.Read(buffer, 0, bufferSize);
                            cs.Write(buffer, 0, bytesRead);
                        } while (bytesRead != 0);
                    }
                }
            }
        }

Beim ausführen, bekomm ich beim verschlüsseln immer am Ende des using-Blocks folgende Exception:

System.Security.Cryptography.CryptographicException: "Die Zeichenabstände sind ungültig und können nicht entfernt werden."

Wie ihr seht, habe ich bereits das Padding ausprobiert, jedoch ohne Erfolg. Bei allen Verianten schlägt es fehl, nur bei Padding.Zeros nicht, da wirft er mir keine Exception, jedoch sieht das Decrypt-File ähnlich wie das Ecnrypt-File aus.

Wenn ich eine .jpg-File versschlüsseln will, bekomm ich die gleiche Exception. Ich habe mich etwas durchgelesen und rausgefunden, dass ich anstatt dem FileStream ein NetworkStream verwenden soll, dann funktioniert das, jedoch bin ich mit meinem Latein am Ende, wie ich das bewerkstelligen soll, da ich nirgends ein Socket-Objekt erstell, was das NetworkStream-Objekt braucht.

Weiß von euch jemand eine Lösung für mein Problem? Vielen, vielen Dank schon mal im voraus!

EDIT: Ich möchte am Ende des Projektes auch Files die >10GB groß sind mit der Variante verschlüsseln. Deshalb war mein Ansatz das File in chunks zu unterteilen und diese an den Server zu schicken.

16.827 Beiträge seit 2008
vor 5 Jahren

Dir ist bewusst, dass Du im Endeffekt das Rad auf einem niedrigen Level (weil TCP) neu entwickelst?
Du könntest auch einfach HTTPS-basierende Verbindungen nehmen zB. via REST und ASP.NET Core.
Bekommst fast alles Geschenkt.

PS: Mit Exceptions auf Englisch bekommst Du bessere Suchergebnisse.
Es empfiehlt sich hier das deutsche Sprachpaket zu deinstallieren.

Z
Z4che Themenstarter:in
2 Beiträge seit 2018
vor 5 Jahren

Ich habe mein Post editiert: Da ich auch Files die >10GB sind ver-/entschlüsseln will, wäre REST doch eher ungeeignet, oder sehe ich das falsch?

Auf Englisch hab ich mir die Exception auch schon angeschaut, da kam ich auf das Padding 😉

286 Beiträge seit 2011
vor 5 Jahren

Eine 10GB-Datei verschickt man idR auch nicht als ganzes sondern partioniert diese (Stichwort Übertragungsfehler: Was machst du wenn bei 9,9GB ein Fehler auftritt, von vor anfangen?). Zudem sollte deine Wahl hier FTP vs HTTP sein, welche beide über TCP/IP laufen. Das ganze direkt mit TCP zu machen ist wie gesagt die Neuerfindung des Rads.

Beste Grüße
emuuu

2+2=5( (für extrem große Werte von 2)

16.827 Beiträge seit 2008
vor 5 Jahren

wäre REST doch eher ungeeignet, oder sehe ich das falsch?

REST ist ein Regelset, das über HTTP gestülpt wird, das die URLs und Response Codes definiert.
Daher kann REST hier kein Faktor, sein, dass es für diesen Fall ungeeignet wäre - REST hat mit einem Uploadsize nichts zutun.

Und nein: weder HTTP, noch REST oder ASP.NET Core ist dafür ungeeignet - aber Dein Prozess ist ungeeignet.
Korrekte wäre es, wenn Du eine Datei in Chunks teilst und diese dann als "chunked upload" nach ASP.NET Core schiebst - über HTTPS.
Der einzig limitierende Faktor ist, wie groß ein Chunk sein darf - und das ist eine Sache, die man im Webserver bzw. in der ASP.NET Core Middleware konfigurieren kann (default in ASP.NET Core aus Sicherheitsgründen "nur" ca. 28 MB).
Und ASP.NET Core wird per default in ner Konsolenanwendung gehostet.

Im Prinzip funktioniert auf dieser Basis jeder File-Dienst wie OneDrive, DropBox und Co...

3.170 Beiträge seit 2006
vor 5 Jahren

Hallo,

Du benutzt offenbar dieselbe Transform(...)-Methode für das Ver- und Entschlüsseln.

Das kann aber nicht funktionieren.
Beim Entschlüsseln müsstest Du den CryptoStream auf der source erstellen und CryptoStreamMode.Read verwenden.

Außerdem ist such ICryptoTransfrom ein IDisposable und sollte disposed werden.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

T
2.222 Beiträge seit 2008
vor 5 Jahren

Würde dir auch von einer Custom Lösung abraten.
Entweder HTTPS oder wenn HTTP nicht erwünscht ist, dann direkt per FTPS.
Du erfindest nicht nur das Rad neu sondern kannst bei einer schlechten Umsetzung, eben durch einen fixen Key, die Kommunikation zwischen Clients und dem Server sehr einfach angreifbar machen.
Wenn dein Key z.B. im Code fix eingetraten ist, liese sich dieser mit ILSpy einfach aus dem Code kopieren.

Hier sollte direkt per HTTPS das Problem mit Transportverschlüsselung sowie dem Schlüsselverteilung direkt gelöst werden.
Die Technik dafür stehen dir mit ASP .NET Core auch direkt zur Verfügung.
Alternativ eben dann einen FTPS Server z.B. mit FileZilla aufsetzen und die Übertragung kann auch ohne Probleme durchgeführt werden.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.