Ошибка при шифровании и расшифровке. Не удалось найти причину исключений

У меня есть следующие два метода.

1-й способ

  //SymmetricEncryting 
 private byte[] SymmetricEncrypt()
  {
  try
      {
        //Get Byte Value 
        byte[] x= Encoding.Default.GetBytes("Test");

        byte [] y;

        //Create Symmetric Key Encription
        RijndaelManaged rijndaelManaged = new RijndaelManaged();

        //GetSymmetricPublicKey
        _symmetricPublicKey = rijndaelManaged.Key;

        //Get Symmetric Public IV
        _symmetricPublicIv = rijndaelManaged.IV;

        using (MemoryStream memoryStream = new MemoryStream(x))
        {
            //Start EncriptionProcess
            var cryptoStream = new CryptoStream(memoryStream,
                                                rijndaelManaged.CreateEncryptor
                                                 (_symmetricPublicKey,
                                                 _symmetricPublicIv),
                                                CryptoStreamMode.Write);

            cryptoStream.Write(x, 0, x.Length);

            // Complete the encryption process
            //cryptoStream.FlushFinalBlock();

            y= memoryStream.ToArray();


        }

        return y;
    }
    catch (Exception)
    {
        throw;
    }
}

2-й способ

private string Decrypt(
    byte[] y,
    byte[] symmetricPublicKey,
    byte[] symmtricPublicIv)
{
    try
    {
        //Create the Key Container
        CspParameters cspParameters = new CspParameters();

        //Get the AsyPrivate and Public key from the Container
        cspParameters.KeyContainerName = "Keys";


        var rsaCryptoServiceProvider = new RSACryptoServiceProvider(cspParameters);

        //Decrypt and get the Symmetric Public key
        var decryptedSymmetricPubk = rsaCryptoServiceProvider.Decrypt(symmetricPublicKey, false);

        //Decrypt and get the Symmetric Public IV
        var decryptedSymmetricPubIv = rsaCryptoServiceProvider.Decrypt(symmtricPublicIv, false);

        //Create RijndaelManaged object to do the Symmtric dycrption
        RijndaelManaged rijndaelManaged = new RijndaelManaged();

        //Create cryptostream using decrypted symmetric Public Key and IV
        ICryptoTransform iCryptoTransform = rijndaelManaged.CreateDecryptor(decryptedSymmetricPubk,
                                                                            decryptedSymmetricPubIv);
        //Create a memory stream 
        using (MemoryStream memoryStream = new MemoryStream(y))
        {

            var cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Read);

            byte[] z= new byte[y.Length];

            cryptoStream.Read(z, 0, z.Length);

            //cryptoStream.FlushFinalBlock();

            //Convert byte array to string
            var x= System.Text.Encoding.Default.GetString(z);

            return x;
        }
    }
    catch (Exception)
    {
        throw;
    }

Как вы видите в коде, я пытаюсь зашифровать строку, используя симметричное шифрование. Я шифрую симметричный открытый ключ и Iv, используя уже созданный асимметричный открытый ключ. Затем я пытаюсь расшифровать зашифрованную строку.

Проблема 1 Какова цель использования cryptoStream.FlushFinalBlock(); как для шифрования, так и для дешифрования. Как я узнал из msdn, это завершит процессы, запущенные в cyptostream

Проблема 2. Если я раскомментирую строку cryptoStream.FlushFinalBlock();, будет выдано исключение "Memory stream is not expandable.". Но если я прокомментирую строку, она будет работать нормально и вернет массив байтов.

Проблема 3 Однако второй метод генерирует исключение "system.security.cryptography.cryptographicexception length of the data to decrypt is invalid при выполнении строки cryptoStream.Read(z, 0, z.Length);

Я не смог найти фактическую причину этих ошибок при отладке. Также я провел поиск в Google. Но, к сожалению, я не смог найти никакого решения. Может ли кто-нибудь объяснить ответ?


person Thabo    schedule 30.05.2012    source источник


Ответы (2)


Вы шифруете с использованием заполнения PKCS (по умолчанию). AES/Rijndael — это блочный шифр, что означает, что он может шифровать только блоки по 16 байт за раз. Чтобы блочный шифр мог шифровать данные произвольного размера, мы используем алгоритм заполнения. PKCS-заполнение работает, добавляя 1-16 байтов в конце при шифровании и удаляя их при расшифровке. Длина заполнения закодирована в самом дополнении.

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

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

Второе исключение связано с тем, что вы удалили оператор FlushFinalBlock и потому, что MemoryStream не разрешено изменять размер для создания массива правильной длины. Зашифрованные данные всегда должны быть кратны 16 байтам, но поскольку MemoryStream будет повторно использовать x, y будет иметь ту же длину, что и x, что не всегда допустимо.

Решение:

  1. Используйте FlushFinalBlock в SymmetricEncrypt.
  2. Замените using (MemoryStream memoryStream = new MemoryStream(x)) и using (MemoryStream memoryStream = new MemoryStream(y)) на using (MemoryStream memoryStream = new MemoryStream()). Это позволит MemoryStreams свободно изменять размер.
person Rasmus Faber    schedule 30.05.2012
comment
Отлично..... Превосходное объяснение. На самом деле это ответ, который я хочу. Я хочу знать, что происходит внутри шнура. Это лучший способ для обучения. Теперь мне ясно, почему мы используем FlushFinalBlock() и что В этой ситуации мы используем пертукулярный метод. Большое спасибо за отличное объяснение. - person Thabo; 30.05.2012

Как ни странно, у меня также работает операция записи при расшифровке. Что-то типа:

var decryptMemoryStream = new MemoryStream();
var decryptStream = new CryptoStream(decryptMemoryStream, iCryptoTransform , CryptoStreamMode.Write);

//write the unencrypted data array to the stream
decryptStream.Write(y, 0, y.Length);
decryptStream.Flush();
decryptStream.Close();

var decryptedData = decryptMemoryStream.ToArray();
person ptat    schedule 05.03.2018