简体   繁体   English

当消息传入使用 AES 加密时,我需要从 NetworkStream 读取多少字节?

[英]How many bytes do I need to read from NetworkStream, when message incoming is encrypted with AES?

I am a student and I am not used to c# or "network programing".我是学生,不习惯 c# 或“网络编程”。 We need to make a client server program, that supports file transfering.我们需要制作一个支持文件传输的客户端服务器程序。 I'm trying to send some information about the file to server, but if server reads more or less bytes, than client sent, program gives exception.我正在尝试将有关文件的一些信息发送到服务器,但是如果服务器读取的字节数多于或少于客户端发送的字节数,则程序会给出异常。 I am asking how can the server side in advance know, the byte size of incoming encrypted message.我在问服务器端如何提前知道传入加密消息的字节大小。

For example: if encrypted sent messages size is 48 bytes and on the server side I read 1024 (and not the exact same size - in this example 48) bytes from stream, program chrashes... The problem is, that the server doesn't know encrypted message size in advance...例如:如果加密发送的消息大小为 48 个字节,并且在服务器端我从 stream 读取 1024 个(而不是完全相同的大小 - 在本例中为 48 个)字节,程序崩溃......问题是,服务器没有事先不知道加密消息的大小...

My program is not even near the final product and I have many other issues too(with GUI freezing without MessageBox.Show("") messages before reading/writing to NetworkStream), but this is my current question.我的程序甚至还没有接近最终产品,而且我还有许多其他问题(在读取/写入 NetworkStream 之前没有 MessageBox.Show("") 消息的 GUI 冻结),但这是我当前的问题。 I also don't know how to set the same IV on server and client side in AES ecncryption, without declaring global IV.我也不知道如何在 AES 加密中在服务器端和客户端设置相同的 IV,而不声明全局 IV。

Here is the whole code:这是整个代码:

    using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;
using System.Linq;

namespace Kodiranje
{
    public partial class Form1 : Form
    {
        const int port = 22222;
        const string ip = "127.0.0.1";
        IPAddress ipServer = IPAddress.Parse(ip);
        TcpListener server = null;
        TcpClient client = null;
        Thread thServer = null;
        NetworkStream dataStream = null;
        string receivedMessage = "";
        bool? izbira = null;
        Aes myAes = Aes.Create();
        bool serverRunning = true;
        bool datotekaIzbrana = false;
        byte[] iv = null;
        string filePath, fileName, fileExtension;
        OpenFileDialog openFileDialog;
        long fileSize;
        long kolicnik;
        long ostanek;


        public Form1()
        {
            InitializeComponent();
            iv = myAes.IV;
            thServer = new Thread(new ThreadStart(startServer));
            thServer.IsBackground = true;
            thServer.Start();
            myAes.Padding = PaddingMode.PKCS7;
            iv = myAes.IV;  // global IV set - how to avoid that?
        }

        void startServer()
        {

            server = new TcpListener(ipServer, port);
            server.Start();
            textBox4.Invoke(new Action(() => textBox4.AppendText("Strežnik: zagnan na: IP: " + ip + ", port:" + port)));
            client = new TcpClient();
            client = server.AcceptTcpClient();

            NetworkStream dataStream = client.GetStream();
            textBox4.Invoke(new Action(() => textBox4.AppendText(Environment.NewLine + "Strežnik: Sprejet nov uporabnik")));


            if (izbira == true)
            {
                byte[] serverPublicKey;
                ECDiffieHellmanCng serverDH = new ECDiffieHellmanCng();
                serverDH.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                serverDH.HashAlgorithm = CngAlgorithm.Sha256;
                serverPublicKey = serverDH.PublicKey.ToByteArray();



                byte[] message = new byte[1024];
                while (!dataStream.DataAvailable) { }
                if (dataStream.DataAvailable)
                    try
                    {
                        dataStream.Read(message, 0, message.Length);
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.ToString());
                    }

                byte[] serverCommoneKey = serverDH.DeriveKeyMaterial(CngKey.Import(message, CngKeyBlobFormat.EccPublicBlob));
                textBox4.Invoke(new Action(() => textBox4.AppendText(Environment.NewLine + "Strežnik: Dobil sem sporočilo: " + receivedMessage)));


                dataStream.Write(serverPublicKey, 0, serverPublicKey.Length);


                // Here I'm reading sent message and I decrypt it, but if the size of new byte[] is 
                not the same as the size of recieved message my program chrashes... how can i avoid               
                chrasing wihtout knowing the message size, and if I for instance set reading size to 
                1024 bytes?                   

                byte[] encryptedMessage = new byte[48]; // for this file i know the sent size from 
                client but in reality, I wouldn't know the exact size...

                while (!dataStream.DataAvailable) { }
                MessageBox.Show(""); // GUI freezes without this message
                dataStream.Read(encryptedMessage, 0, encryptedMessage.Length);
                string prejetoSporocilo = odkodirajString(serverCommoneKey, encryptedMessage);
                MessageBox.Show("Odkodirano prejeto sporočilo:" + prejetoSporocilo);

            }


            else // irrelevant
            {
                byte[] message = new byte[1024];
                message = Encoding.UTF8.GetBytes("serbus");
                dataStream.Write(message, 0, message.Length);


            }
            while (serverRunning) { }

        }



        void button1_Click(object sender, EventArgs e)
        {
            if (izbira == null)
            {
                this.textBox4.AppendText(Environment.NewLine + "Izbrati morate ali boste datoteko prenesli ali poslali!");
                return;
            }
            if (!datotekaIzbrana)
            {
                MessageBox.Show("Izberite datoteko!");
                return;
            }

            this.button2.Enabled = true;
            this.button4.Enabled = false;

            this.button1.Enabled = false;
            this.button3.Enabled = true;
            client = new TcpClient();
            IPAddress insertedIp = IPAddress.Parse(textBox1.Text);


            byte[] clientPublicKey;
            ECDiffieHellmanCng clientDH = new ECDiffieHellmanCng();
            clientDH.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
            clientDH.HashAlgorithm = CngAlgorithm.Sha256;
            clientPublicKey = clientDH.PublicKey.ToByteArray();


            client.Connect(insertedIp, Convert.ToInt32(textBox3.Text));
            dataStream = client.GetStream();


            if (izbira == true)
            {

                dataStream.Write(clientPublicKey, 0, clientPublicKey.Length);

                byte[] message = new byte[1024];

                MessageBox.Show(""); // GUI freezes without this message
                while (true)
                {
                    if (dataStream.DataAvailable)
                    {

                        dataStream.Read(message, 0, message.Length);
                        this.textBox4.AppendText(Environment.NewLine + "Client: Dobil sem sporočilo: " + receivedMessage);
                        break;
                    }
                }
                byte[] clientCommoneKey = clientDH.DeriveKeyMaterial(CngKey.Import(message, CngKeyBlobFormat.EccPublicBlob));


                message = new byte[1024];

                /// here I'm trying to send file information, then encrypt it and send it to server

                kolicnik = fileSize / 1024;
                ostanek = fileSize % 1024;
                string glava = fileName + "|" + fileExtension + "|" + fileSize.ToString() + "|" + kolicnik.ToString() + "|" + ostanek + "|";

                //MessageBox.Show(glava);
                message = Encoding.UTF8.GetBytes(glava);
                MessageBox.Show("velikost stringa: " + glava.Length + " velikost bitov: " + message.Length);
                message = kodirajString(clientCommoneKey,glava);
                MessageBox.Show("Zakodiran size: " + message.Length);
                dataStream.Write(message, 0, message.Length);





                ///


            }


            else // irrelevant
            {

                byte[] message = new byte[1024];
                while (!dataStream.DataAvailable)
                { }
                dataStream.Read(message, 0, message.Length);

                receivedMessage = Encoding.UTF8.GetString(message);
                this.textBox4.AppendText(Environment.NewLine + "Strežnik: Dobil sem sporočilo: " + receivedMessage);
            }
        }



        void buttonUpload_Click(object sender, EventArgs e)
        {
            izbira = true;
            this.buttonDownload.Enabled = false;
            this.button4.Enabled = true;
        }
        void buttonDownload_Click(object sender, EventArgs e) // irrelevant
        {
            izbira = false;
            this.buttonUpload.Enabled = false;
            this.button2.Text = "Prenesi";
        }

        void button3_Click(object sender, EventArgs e)
        {
            serverRunning = false;
        }

        void button4_Click(object sender, EventArgs e) // choose file
        {
            openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "IZBERI DATOTEKO";
            openFileDialog.Filter = "GIF Image|*.gif|text file|*.txt|PDF file|*.pdf";
                if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                //break;
                datotekaIzbrana = true;
                filePath = openFileDialog.FileName;
                this.textBox4.AppendText(Environment.NewLine + "Pot do datoteke:" + filePath);
                fileName = openFileDialog.SafeFileName;
                fileExtension = Path.GetExtension(filePath);
                string getPath = @filePath;
                FileInfo info = new FileInfo(getPath);

                Stream file = File.OpenRead(filePath);
                fileSize = info.Length;
                fileName = Path.GetFileNameWithoutExtension(info.Name);



            }
            else {
                    MessageBox.Show("IZBERITE DATOTEKO!");
                }


        }

        void button2_Click(object sender, EventArgs e)
        {

        }

        byte[] kodirajString(byte[] commonKey, string messageToEncrypt)  // encrypt message
        {
            myAes = Aes.Create();
            myAes.Padding = PaddingMode.PKCS7;
            myAes.Key = commonKey;
            myAes.IV = iv;
            ICryptoTransform encryptor = myAes.CreateEncryptor(myAes.Key, iv);
            byte[] encrypted;
            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(messageToEncrypt);

                    }
                    encrypted = msEncrypt.ToArray();
                    int s = encrypted.Length;
                    MessageBox.Show("Velikost " + s.ToString());
                    return encrypted;

                }
            }
        }


        string odkodirajString(byte[] commonKey, byte[] encryptedMessage) {  // decrypt message
            myAes = Aes.Create();
            myAes.Padding = PaddingMode.PKCS7;
            myAes.Key = commonKey;
            // Create a decryptor to perform the stream transform.
            ICryptoTransform decryptor = myAes.CreateDecryptor(myAes.Key, iv);

            // Create the streams used for decryption.
            using (MemoryStream msDecrypt = new MemoryStream(encryptedMessage))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        string plaintext;
                        plaintext = srDecrypt.ReadToEnd();
                        MessageBox.Show("Sprejeto sporočilo " + plaintext);
                        return plaintext;
                    }
                }
            }
        }

    }
}

I thank you in advance!我提前谢谢你!

You need to build a protocol over the top of TCP.您需要在 TCP 之上构建一个协议。

eg,例如,

 [char[6]] VersionCode
 [int] length
 [byte[length]] payload

Now you can read the first 10 bytes.现在您可以读取前 10 个字节。 Check that the Version code matches your programs version, and then from that you can get the [length] which will tell you how many bytes to read.检查版本代码是否与您的程序版本匹配,然后您可以从中获取 [length] ,它将告诉您要读取多少字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在protobuf-net中告诉DeserializeWithLengthPrefix调用从NetworkStream读取了多少字节 - How to tell in protobuf-net how many bytes were read from a NetworkStream on a call to DeserializeWithLengthPrefix C#:使用Unicode编码从聊天的NetworkStream中读取多少个字节? - C#: How many bytes to read from a NetworkStream of a chat using a Unicode encoding? 从NetworkStream读取前6个字节? - Read First 6 Bytes From NetworkStream? 从NetworkStream读取字节(挂起) - Read bytes from NetworkStream (Hangs) 如何确定何时无法在NetworkStream中读取数据? - How do I determine when there is no more data to read in a NetworkStream? 如何使用NetworkStream正确处理传入的protobuf消息? - How to properly handle incoming protobuf message with a NetworkStream? 来自NetworkStream的Write()和Read()原始字节,某些字节的数据存在差异 - Write() and Read() raw bytes from NetworkStream, data is difference at some bytes 从NetworkStream获取数据时,如何读取带有子元素的完整XML元素? - How do I read a complete XML Element with its children while getting data from NetworkStream? 在循环读取时,NetworkStream.Read()产生重复的字节 - NetworkStream.Read() produce repetitive bytes when reading in loop 如何实现附加到加密消息的IV的AES - How to implement AES with IV attached to the encrypted message
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM