Почему я получаю System.Security.Cryptography.CryptographicException во время расшифровки этого байтового массива - PullRequest
0 голосов
/ 08 января 2019

Я только начал с криптографии в C # и попытался сначала зашифровать, а затем расшифровать файл. Но во время расшифровки, в функции приватный статический байт [] Расшифровать (байт [] inputBuffer) , в byte [] outputBuffer = transform.TransformFinalBlock (inputBuffer, 0, inputBuffer.Length); Я получаю следующее исключение: System.Security.Cryptography.CryptographicException: «Неверные данные». Но почему это так?

Это функция для чтения файла:

private static void DecryptFile()
{
    byte[] buffer = new byte[4096];
    byte[] decryptionBuffer = new byte[4096];
    int bytesRead = 0;
    using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Encrypted.txt"))
    {
        using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\\Decrypt.mp3"))
        {
            while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                decryptionBuffer = Decrypt(buffer);
                outputStream .Write(decryptionBuffer, 0, decryptionBuffer.Length);
            }
        }
        Console.WriteLine("Done.");
    }
}

Это функция для расшифровки файла, ключа и вектора инициализации:

private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };

private static byte[] Decrypt(byte[] inputBuffer)
{
    SymmetricAlgorithm algorithm = DES.Create();
    ICryptoTransform transform = algorithm.CreateDecryptor(key, iv);
    //here the exception is triggered
    byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
    return outputBuffer;
}

вот как файл был зашифрован:

private static void EncryptFile()
{
    byte[] buffer = new byte[4096];
    byte[] enryptionBuffer = new byte[4096];
    int bytesRead = 0;
    using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Test.txt"))
    {
        using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\\Encrypted.txt"))
        {
            while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                encryptionBuffer = Encrypt(buffer);
                outputStream .Write(encryptionBuffer, 0, encryptionBuffer.Length);
            }
        }
        Console.WriteLine("Done.");
    }
}

//Key and initialization vector are the same
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };

private static byte[] Encrypt(byte[] inputBuffer)
{
    SymmetricAlgorithm algorithm = DES.Create();
    ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
    byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
    return outputBuffer;
}

1 Ответ

0 голосов
/ 08 января 2019

Ваш код шифрования создает большие выходные буферы, чем ваши входные буферы. Если вы независимо шифруете 4096 байтов за раз, он выдает 4104 байта вывода 1 . Если вы хотите продолжать независимо шифровать каждый блок вашего файла, вам нужно изменить код дешифрования, чтобы использовать 4104-байтовые буферы, когда он работает кусками.

В идеале, это «шифрование каждого блока отдельно» не является обязательным требованием. Если это так, создайте свой transform объект один раз , а не один раз каждый раз в цикле. И используйте Transform вместо TransformFinalBlock до тех пор, пока не узнаете, что достигли конца файла (однако обратите внимание, что они возвращают очень разные вещи).

Вы также игнорируете bytesRead, который сообщает , сколько вашего буфера заполнено полезными данными . Вы также должны использовать это и не делать ваш окончательный раунд шифрования x много байтов, которые являются последними байтами файла и bufferSize - x байтов предыдущего блока данных из файла .

Возможно, я бы вместо этого хотел создать CryptoStream, который обернет один из ваших FileStream объектов, а затем использовать Stream.CopyTo или моральные эквиваленты для выполнения этой работы. Пусть библиотеки беспокоятся об управлении буферами, циклами и т. Д.

И, наконец, в идеале, вы понимаете, что наступил 2019 год, и поэтому совершенно неуместно писать новый код, который использует DES для шифрования 2


1 Эта программа, если вы установите точку останова в строке Console.ReadLine, имеет c, содержащую 4104 байта:

using System;
using System.Security.Cryptography;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var b = new byte[4096];
        var c = Encrypt(b);
        Console.ReadLine();
    }

    private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
    private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };

    private static byte[] Encrypt(byte[] inputBuffer)
    {
        SymmetricAlgorithm algorithm = DES.Create();
        ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
        byte[] outputBuffer = transform.TransformFinalBlock(
                                inputBuffer,
                                0,
                                inputBuffer.Length);
        return outputBuffer;
    }
}

2 Таким образом, мой EnryptFile в целом будет:

private static void EncryptFile()
{
    using (var inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Test.txt"))
    using (var outputStream = File.Create(Environment.CurrentDirectory + "\\Encrypted.txt"))
    using (var aes = Aes.Create())
    using (var cStream = new CryptoStream(
                               inputStream,
                               aes.CreateEncryptor(key, iv),
                               CryptoStreamMode.Read))
    {
        cStream.CopyTo(outputStream);
    }
}

Или вариант async, который использует await cStream.CopyToAsync(outputStream); в качестве самого внутреннего утверждения. DecryptFile будет аналогичным образом упрощен.

...