Проблемы с расшифровкой данных с помощью Rijndael после отправки через System.Net.Socket

Я следовал руководству с YouTube, http://tinyurl.com/ljvzjqk и http://tinyurl.com/os7vlgr и попытался реализовать это в проекте клиент/сервер, над которым я работаю. Я могу шифровать и расшифровывать строки в клиентской программе просто отлично, но когда данные получены на сервере, он не расшифровывает их правильно.

Во время отладки я мог видеть, что byte[], несущий данные, абсолютно одинаков на обоих концах.

В обеих программах это объявлено в классе:

static SymmetricAlgorithm rjnObj;
static byte[] Key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };

Сервер:

static void Main(string[] args)
    {
        rjnObj = Rijndael.Create();
        rjnObj.Padding = PaddingMode.Zeros;
        rjnObj.Key = Key;

        Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1980);

        serverSocket.Bind(localEP);
        serverSocket.Listen(10);
        serverSocket = serverSocket.Accept();
        while(true)
        {
            byte[] dataReceived = new byte[1024];
            int lengthOfData = serverSocket.Receive(dataReceived);
            byte[] dataReceived2 = new byte[lengthOfData];
            for (int i = 0; i < lengthOfData; i++)
            {
                dataReceived2[i] = dataReceived[i];
            }
            Console.WriteLine("Received: {0}", Encoding.UTF8.GetString(dataReceived2));
            Console.WriteLine("Decrypted: {0}", Decrypt(dataReceived2));
        }
    }
    public static string Decrypt(byte[] cipherbytes)
    {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(cipherbytes);
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateDecryptor(), CryptoStreamMode.Read);

        cs.Read(cipherbytes, 0, cipherbytes.Length);
        byte[] plainBytes = ms.ToArray();
        cs.Close();
        ms.Close();

        return Encoding.UTF8.GetString(plainBytes);
    }

Клиент:

static void Main(string[] args)
    {
        rjnObj = Rijndael.Create();
        rjnObj.Padding = PaddingMode.Zeros;
        rjnObj.Key = Key;

        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1980);

        try
        {
            clientSocket.Connect(serverEP);
            Console.WriteLine("Connected to {0}.", clientSocket.RemoteEndPoint);

            while(true)
            {
                Console.Write("String to send: ");
                byte[] dataToSend = Encrypt(Console.ReadLine());
                clientSocket.Send(dataToSend);

                Console.WriteLine("Encrypted string: {0}", Encoding.UTF8.GetString(dataToSend));
                Console.WriteLine("Decrypted string: {0}", Decrypt(dataToSend));
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Something went wrong...");
            Console.WriteLine(e.ToString());
            Console.ReadKey();
        }
    }
    public static byte[] Encrypt(string s)
    {
        byte[] plainBytes = Encoding.UTF8.GetBytes(s);
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateEncryptor(), CryptoStreamMode.Write);

        cs.Write(plainBytes, 0, plainBytes.Length);
        cs.Close();
        byte[] cipherbytes = ms.ToArray();
        ms.Close();

        return cipherbytes;
    }
    public static string Decrypt(byte[] cipherbytes)
    {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(cipherbytes);
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateDecryptor(), CryptoStreamMode.Read);

        cs.Read(cipherbytes, 0, cipherbytes.Length);
        byte[] plainBytes = ms.ToArray();
        cs.Close();
        ms.Close();

        return Encoding.UTF8.GetString(plainBytes);
    }

Вывод клиентской программы:

Connected to 127.0.0.1:1980.
String to send: Hello server!
Encrypted string: ?*?8?2?HfG▲z  ?K
Decrypted string: Hello server!
String to send:

Вывод из серверной программы:

Received: ?*?8?2?HfG▲z  ?K
Decrypted: E??diQ♣?ZX??♂?z

Как видите, зашифрованная строка на сервере равна зашифрованной строке на клиенте, поэтому я предполагаю, что это как-то связано с rjnObj, и что этот объект не идентичен на обоих концах.

Приведенный здесь код является новым решением, которое я создал, чтобы задать этот вопрос. Я использовал PaddingMode.Zeros, потому что когда я попробовал PKCS7, я получил исключение.

В серверном коде я сделал еще один byte[] dataReceived2, чтобы он был точной длиной полученного byte[]. Я нашел другие примеры кода, который отправляет зашифрованные данные по сети, но в этих примерах используются TcpClient и NetworkStream. В решении, над которым я работаю для школьного проекта, я использую сокеты, и я действительно не хочу переписывать решение.

Если кто-то может помочь мне с этим, это было бы здорово! Спасибо!


person dissar    schedule 09.11.2014    source источник


Ответы (2)


Попробуйте использовать тот же IV. Я считаю, что когда вы создаете новый экземпляр Rijndael.Create(), Key и IV будут сгенерированы случайным образом. Вы только устанавливаете ключ, но для этого вам также нужно использовать тот же IV.

На клиенте вы используете тот же экземпляр Rijndael, поэтому шифрование и дешифрование работают нормально.

Вы можете просмотреть документацию и пример использования класса Rijndael здесь. Что мне нравится в этом, так это использование утверждений. Это выглядит чище, поскольку потоки закрываются, как только они больше не используются.

person pepo    schedule 09.11.2014

Ваш метод расшифровки на сервере вообще не имеет никакого смысла. Поскольку вы сделали это сейчас, вы должны читать из cs Stream в массив открытого текста. Или вы можете по-разному распределять потоки и записывать зашифрованный текст в поток cs и извлекать открытый текст из основного потока памяти. Я думаю, что последний метод чище и проще.

person President James K. Polk    schedule 09.11.2014