C # Отправить байт [] на сервер, расшифровать содержимое и отправить его как байт [] обратно клиенту - PullRequest
0 голосов
/ 07 декабря 2018

Моя проблема заключается в следующем:

У меня клиент-серверное приложение, подключенное через сокеты.Задача моего клиента - отправить файл побайтно на сервер.Сервер получает байты, расшифровывает их, отправляет обратно клиенту, и он записывает их в новый файл на диске.

Я получаю каждый раз исключение на стороне сервера (System.Security.Cryptography.Exception: заполнение недопустимо и не может быть удалено) в этой строке кода: plaintext = sr.ReadToEnd ();

Couldкто-нибудь помочь мне решить мою проблему?

Вот код дешифрования:

public byte[] Dec(byte[] content, byte[] Key, byte[] IV, int fileLength, string filepath, int chunkSize, int bytesToRead)
    {
        byte[] contentDec;
        string plaintext = null;
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;

            ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);


            using (MemoryStream ms = new MemoryStream(content))
            {
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader sr = new StreamReader(cs))
                    {
                        plaintext = sr.ReadToEnd();
                        cs.FlushFinalBlock();
                    }
                    contentDec = encoding.GetBytes(plaintext);
                }
            }
        }
        return contentDec;
    }

Вот мой код шифрования:

    public byte[] Enc(byte[] content,byte[] Key, byte[] IV, int fileLength,string filepath, int chunkSize, int bytesToRead)
    {
        byte[] contentEnc;
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");
        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;
            ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter sw = new StreamWriter(cs))
                    {
                        sw.Write(content);
                    }
                    contentEnc = ms.ToArray();
                }
            }
        }
        return contentEnc;
    }

На стороне клиента я вызываю такой метод шифрования

        int chunkSize = 1024;
        byte[] chunk = new byte[chunkSize];
        using (FileStream fileReader = new FileStream(plainPath, FileMode.Open, FileAccess.Read))
        using (FileStream filewriter = new FileStream(pathEncrypt, FileMode.Create, FileAccess.ReadWrite))
        using (BinaryReader binaryReader = new BinaryReader(fileReader))
        using (RijndaelManaged myRijndael = new RijndaelManaged())
        {
            myRijndael.GenerateKey();
            myRijndael.GenerateIV();
            Key = myRijndael.Key;
            IV = myRijndael.IV;
            int bytesToRead = (int)fileReader.Length;
            do
            {
                chunk = service.Enc(binaryReader.ReadBytes(chunkSize), Key, IV,(int)fileReader.Length, 
                    fileReader.Name, chunkSize, bytesToRead);
                filewriter.Write(chunk, 0, chunk.Length);
                bytesToRead -= chunkSize;
            } while (bytesToRead > 0);
        }

Ключ и IV объявляются как закрытый байт []

На стороне клиента я вызываю метод дешифрования следующим образом

        int chunkSize = 1024;
        byte[] chunk = new byte[chunkSize];
        using (FileStream fileReader = new FileStream(pathEncrypt, FileMode.Open, FileAccess.Read))
        using (FileStream filewriter = new FileStream(pathDecrypt, FileMode.Create, FileAccess.ReadWrite))
        using (BinaryReader binaryReader = new BinaryReader(fileReader))
        {
            int bytesToRead = (int)fileReader.Length;

            do
            {
                chunk = service.Dec(binaryReader.ReadBytes(chunkSize), Key, IV, (int)fileReader.Length, 
                    fileReader.Name, chunkSize, bytesToRead);
                filewriter.Write(chunk, 0, chunk.Length);
                bytesToRead -= chunkSize;
            } while (bytesToRead > 0);
        }

Редактировать: Это установление моего соединения между клиентом и сервером.

Сервер: var host = new ServiceHost (typeof (Service), новый Uri ("net.pipe: // localhost"));

        host.AddServiceEndpoint(typeof(TiService),
                                new NetNamedPipeBinding(), "TestService");
        host.Open();
        Console.WriteLine("Server connection established...");
        Console.ReadKey();

Клиент:

var callback = new Callback();
var context = new InstanceContext(callback);
var pipeFactory =
new DuplexChannelFactory<TiService>(context,
new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/TestService"));

service = pipeFactory.CreateChannel();
service.Connect();

1 Ответ

0 голосов
/ 07 декабря 2018

Ваша проблема начинается с использования StreamWriter в шифровании.Он предназначен для написания текстового файла, а не произвольного файла.Когда вы вызываете sw.Write (content), он просто вызывает content.ToString (), который возвращает «System.Byte []» вместо того, что вы, вероятно, ожидаете, каждый байт массива.Чтобы это исправить, просто напишите CryptoStream, не нужно использовать StreamWriter, например:

using (var rijAlg = new AesCng())
{
    rijAlg.Key = Key;
    rijAlg.IV = IV;
    ICryptoTransform encryptor = rijAlg.CreateEncryptor();
    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
            cs.Write(content, 0, content.Length);               
        }
        contentEnc = ms.ToArray();
    }
}

Вы, наверное, заметили, что я использовал AesCng вместо RijndaelManaged.Зачем?Потому что в моем тесте это намного быстрее, и если вам не нужен нестандартный блок, использование RijndaelManaged не дает никаких преимуществ.Кроме того, я использую CreateEncryptor без параметров, потому что вы уже установили Key & IV в предыдущих строках.

То же самое в расшифровке.Вы не должны рассматривать их как текст, таким образом:

var buffer = new byte[content.Length]; //at first its size is actual size+padding

using (var rijAlg = new AesCng())
{
    rijAlg.Key = Key;
    rijAlg.IV = IV;

    ICryptoTransform decryptor = rijAlg.CreateDecryptor();

    using (MemoryStream ms = new MemoryStream(content))
    {
        using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
        {
            var actualSize = cs.Read(buffer, 0, content.Length);
            //we write the decrypted content to the buffer, and get the actual size

            Array.Resize(ref buffer, actualSize);
            //then we resize the buffer to the actual size
        }
    }
}
return buffer;

Кроме того, использование вами Enc и Dec излишне сложно.Он уже способен обрабатывать весь файл сам по себе.Поэтому, чтобы зашифровать файл, просто используйте

var original = File.ReadAllBytes("originalPath");
var enc = Enc(original, rM.Key, rM.IV);
File.WriteAllBytes("encryptedPath", enc);

А чтобы расшифровать файл, просто используйте

var enc = File.ReadAllBytes("encryptedPath");
var dec = Dec(enc, rM.Key, rM.IV);
File.WriteAllBytes("decryptedPath", dec);

Как видите, я выбрасываю fileLength, filepath, chunkSize иbytesToRead на Enc & Dec, потому что ваш текущий код на самом деле не использует их в любом случае.Я пробовал код с коротким текстовым файлом на ASCII, Unicode и UTF-8, а также с большими двоичными файлами, все они успешно зашифрованы и расшифрованы с идентичным хешем для окончательно расшифрованных файлов.

Редактировать:

Превращение кода в дело прямой записи файлового потока на самом деле делает все намного проще.

public static 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);
            }
        }

    }


}

public static void Enc(string source, byte[] Key, byte[] IV, string target)
{
    using (var rijAlg = new AesCng())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;
        ICryptoTransform encryptor = rijAlg.CreateEncryptor();
        Transform(source, target, encryptor);
    }

}
public static void Dec(string source, byte[] Key, byte[] IV, string target)
{
    using (var rijAlg = new AesCng())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;
        ICryptoTransform decryptor = rijAlg.CreateDecryptor();
        Transform(source, target, decryptor);
    }

}

Использование:

Enc(@"originalPath", key, iv, @"encryptedPath");
Dec(@"encrypedPath", key, iv, @"decryptedPath");
...