Продолжайте получать «CryptographicException: дополнение является недопустимым и не может быть удалено». ошибки с шифрованием AES CBC даже при заполнении - PullRequest
0 голосов
/ 11 ноября 2019

Я просмотрел другие посты на эту тему, но, похоже, не могу понять мою ошибку с этим. Я пытаюсь потоковое шифрование файлов с AES CBC (позже я сделаю другие). Я знаю, что мне нужно заполнить CBC и настроить его. Тем не менее, я получаю ошибку все ту же ошибку.

 Message: 
 System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
     Stack Trace: 
  UniversalCryptoDecryptor.DepadBlock(Byte[] block, Int32 offset, Int32 count)
  UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
  UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
  CryptoStream.ReadAsyncCore(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken, Boolean useAsync)
  CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count)
  EncryptionFunctions.AESDecryptCBC(String encryptedFile, String plainTextFile, Byte[] key, Byte[] iv, Int32 blockSize, Int32 bufferSize) line 82
  EncryptionFunctionsUnitTests.TestEncryptAndDecryptFiles() line 39

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

Это две функции, которые я использую для шифрования и дешифрования.

 public static void AESEncryptCBC(string plainTextFile, string encryptedFile, byte[] key, byte[] iv, int bufferSize = 65536)
    {
        using (FileStream fileStreamOutput = new FileStream(encryptedFile, FileMode.Create)) {
            using (FileStream fileStreamInput = new FileStream(plainTextFile, FileMode.Open))
            {
                using (Aes aes = Aes.Create())
                {
                    aes.Key = key;
                    aes.KeySize = key.Length*8; // Keysize is in bits, bytes to bits conversion
                    aes.BlockSize = 128; // bits
                    aes.Mode = CipherMode.CBC;
                    aes.IV = iv;
                    aes.Padding = PaddingMode.PKCS7;

                    using (CryptoStream cryptoStream = new CryptoStream(fileStreamOutput, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        int read;
                        byte[] readBuffer = new byte[bufferSize];

                        while ((read = fileStreamInput.Read(readBuffer, 0, readBuffer.Length)) > 0)
                        {
                            cryptoStream.Write(readBuffer, 0, read);
                        }
                    }
                }
            }
        }

    }

    public static void AESDecryptCBC(string encryptedFile, string plainTextFile, byte[] key, byte[] iv, int bufferSize = 65536)
    {
        using (FileStream fileStreamOutput = new FileStream(plainTextFile, FileMode.Create))
        {
            using (FileStream fileStreamInput = new FileStream(encryptedFile, FileMode.Open))
            {
                using (Aes aes = Aes.Create())
                {
                    aes.Key = key;
                    aes.KeySize = key.Length * 8; // Keysize is in bits, bytes to bits conversion
                    aes.BlockSize = 128; // bits
                    aes.Mode = CipherMode.CBC;
                    aes.IV = iv;
                    aes.Padding = PaddingMode.PKCS7;

                    using (CryptoStream cryptoStream = new CryptoStream(fileStreamInput, aes.CreateDecryptor(), CryptoStreamMode.Read))
                    {
                        int read;
                        byte[] readBuffer = new byte[bufferSize];

                        while ((read = cryptoStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                        {
                            fileStreamOutput.Write(readBuffer, 0, read);
                        }
                    }
                }
            }
        }
    }

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

 public void TestEncryptAndDecryptFiles()
    {
        string outFile = "out.txt";
        string outFile2 = "out2.txt";

        byte[] salt = new byte[128];
        RandomNumberGenerator.Fill(salt);

        int numberOfBits = 256;
        int blockSize = 128;
        byte[] key = new byte[numberOfBits / 8];
        byte[] iv = new byte[blockSize /8];
        RandomNumberGenerator.Fill(key);
        RandomNumberGenerator.Fill(iv);
        EncryptionFunctions.AESEncryptCBC(SampleText, outFile, key, iv);
        Assert.IsTrue(File.Exists(outFile));

        EncryptionFunctions.AESDecryptCBC(outFile, outFile2, key, iv);
        Assert.IsTrue(File.Exists(outFile2));
        Assert.AreEqual(HashFunctions.Md5(SampleText), HashFunctions.Md5(outFile2));

    }
}

Ответы [ 2 ]

1 голос
/ 11 ноября 2019

Когда вы устанавливаете свойство KeySize, оно создает новый ключ. Когда вы устанавливаете свойство Key, оно обновляет KeySize в соответствии с тем, что было установлено.

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

Вызов CreateEncryptor(key, iv) решает эту проблему, не перечитывая свойства, которые больше не имеют значения.

0 голосов
/ 11 ноября 2019

Хорошо, разобрался, мне нужно было изменить код, чтобы использовать aes.CreateEncryptor(key,iv). Наконец, я обнаружил, что вызов CreateEncryptor() или CreateEncryptor(null, null) автоматически генерирует как вектор инициализации, так и ключ, который перезаписывает те, которые я установил с наборами aes.key и aes.iv. Вроде глупо, я могу установить их, а затем перезаписать с помощью функции, которая явно не собирается это делать. Возможно, это ошибка, поскольку на одной странице написано: «Создает объект симметричного шифратора с текущим свойством Key и вектором инициализации (IV)». Это не делается на основе кода, который у меня был ранее.

В любом случае я нашел это на https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.symmetricalgorithm.generateiv?view=netframework-4.8#System_Security_Cryptography_SymmetricAlgorithm_GenerateIV

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...