Почему RijndaelManaged и AesCryptoServiceProvider возвращают разные результаты?

Вот пример, который я запустил. Он имеет тот же режим, Padding, BlockSize, KeySize. Я использую тот же вектор инициализации, ключ и данные.

Использование RijndaelManaged создает зашифрованное значение: 0x8d,0x81,0x27,0xc6,0x3c,0xe2,0x53,0x2f,0x35,0x78,0x90,0xc2,0x2e,0x3b,0x8a,0x61, 0x41,0x47,0xd6,0xd0xx,0x92,0x72,0x3d,0xc6,0x16,0x2b,0xd8,0xb5,0xd9,0x12,0x85

Использование AesCryptoServiceProvider создает зашифрованное значение: 0x8d,0x9f,0x6e,0x99,0xe9,0x54,0x8b,0x12,0xa9,0x88,0x1a,0x3d,0x65,0x23,0x9c,0x4e, 0x18,0x531,0x18,0x531,0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a, 0x18,0x5a,0x75,0xc5,0x9e,0x0d,0x43,0xe9,0x86,0xd4,0xf3,0x64,0x3a

Вот код, который я использовал для получения этих результатов


   public partial class AesTest
   {
      private SymmetricAlgorithm mEncryptionType;
      private byte[] mPrivateKey;
      private byte[] mInitializationVector;
      private byte[] mData;

      public AesTest()
      {
         mPrivateKey = new byte[32] 
         { 
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22,
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22, 
            0x22, 0x22, 0x22, 0x22
         };

         mInitializationVector = new byte[16]
         { 
            0x33, 0x33, 0x33, 0x33,
            0x33, 0x33, 0x33, 0x33,
            0x33, 0x33, 0x33, 0x33,
            0x33, 0x33, 0x33, 0x33
         };

         mData = new byte[16]
         {
            0x44, 0x44, 0x44, 0x44,
            0x44, 0x44, 0x44, 0x44,
            0x44, 0x44, 0x44, 0x44,
            0x44, 0x44, 0x44, 0x44
         };

         mEncryptionType = new RijndaelManaged();
         mEncryptionType.Mode = CipherMode.CFB;
         mEncryptionType.Padding = PaddingMode.PKCS7;
         mEncryptionType.BlockSize = 128;
         mEncryptionType.KeySize = 256;

         byte[] rij_encrypted_data = Encrypt(mData);

         mEncryptionType = new AesCryptoServiceProvider();
         mEncryptionType.Mode = CipherMode.CFB;
         mEncryptionType.Padding = PaddingMode.PKCS7;
         mEncryptionType.BlockSize = 128;
         mEncryptionType.KeySize = 256;

         byte[] aes_encrypted_data = Encrypt(mData);
      }

      public virtual byte[] Encrypt(byte[] unencryptedData)
      {
         return TransformData(unencryptedData, mEncryptionType.CreateEncryptor(mPrivateKey, mInitializationVector));
      }

      private byte[] TransformData(byte[] dataToTransform, ICryptoTransform cryptoTransform)
      {
         byte[] result = new byte[0];
         if (dataToTransform != null && cryptoTransform != null && dataToTransform.Length > 0)
         {
            // Create the memory stream to store the results
            MemoryStream mem_stream = new MemoryStream();
            // Create the crypto stream to do the transformation
            CryptoStream crypto_stream = new CryptoStream(mem_stream, cryptoTransform, CryptoStreamMode.Write);
            // bytes are transformed on a write
            crypto_stream.Write(dataToTransform, 0, dataToTransform.Length);
            // Flush the final block
            crypto_stream.FlushFinalBlock();
            // Convert the transformed memory stream back to a byte array
            result = mem_stream.ToArray();
            // Close the streams
            mem_stream.Close();
            crypto_stream.Close();
         }
         return result;
      }
   }

Я думаю, мне просто интересно, если я что-то пропустил.

Обновление: Оказывается, что AesManaged вызовет исключение CryptographicException ("указанный режим шифрования недопустим для этого алгоритма"), если вы попытаетесь установить для CipherMode значение CFB. Я чувствую, что AesCryptoServiceProvider должен делать то же самое, но это не так. Забавно, что сертифицированный класс FIPS допускает недопустимые режимы шифрования.

3 ответа

Решение

Ответ от Microsoft:

RijndaelManaged класс и AesCryptoServiceProvider Класс это две разные реализации. RijndaelManaged class - это своего рода реализация алгоритма Rijndael в среде.net, которая не была проверена в рамках программы проверки криптографического модуля (CMVP) NIST (Национальный институт стандартов и технологий).

Тем не мение, AesCryptoServiceProvider Класс вызывает Windows Crypto API, который использует RSAENH.DLL и был проверен NIST в CMVP. Хотя алгоритм Rijndael был победителем конкурса NIST по выбору алгоритма, который станет AES, между Rijndael и официальным AES есть некоторые различия. Следовательно, класс RijndaelManaged и AesCryptoServiceProvider класс имеет тонкие различия по реализации.

К тому же, RijndaelManaged Класс не может обеспечить эквивалентную реализацию с AES. Есть еще один класс, реализованный в.net Framework, AesManaged учебный класс. Этот класс только что завернутый RijndaelManaged класс с фиксированным размером блока и количеством итераций для достижения стандарта AES. Тем не менее, он не поддерживает размер обратной связи, особенно, когда режим установлен как CFB или OFB, CryptographicException будет брошен.

Для получения дополнительной информации, пожалуйста, обратитесь к следующим документам MSDN.

Класс AesManaged и свойство AesManaged.Mode

Если вы хотите выбрать стандартный AES в качестве алгоритма безопасности в вашем приложении, мы рекомендуем использовать AesCryptoServiceProvider учебный класс. Если вы хотите смешать RijndaelManged класс и AesCryptoServiceProvider класс в вашем приложении, мы предлагаем использовать режим CBC вместо режима CFB в вашей программе, так как реализация режима CBC в обоих классах одинакова.

Я думаю, что это связано с CipherMode.CFB. Смотрите этот пост с описанием AesManaged:

AesManaged - это всего лишь оболочка для RinjdaelManaged с добавлением некоторого кода, чтобы убедиться, что вы не настроили алгоритм для работы не-AES-совместимым способом. Например, AesManaged не позволяет вам изменять размер блока. (Это также запретит использование режимов CFB и OFB из-за способа работы RijndaelManaged с этими режимами).

Обратите внимание, что если вы используете CipherMode.ECB или CipherMode.CBC, вы увидите идентичные результаты. Любая причина, почему вам нужен CFB, а не CBC?

Дополнительная информация из этого поста гласит:

По сути, если вы хотите использовать RijndaelManaged в качестве AES, вам необходимо убедиться, что:
1) Размер блока установлен на 128 бит
2) Вы не используете режим CFB, или если у вас есть размер обратной связи также 128 бит

Ок, отлично. Я добавил mEncryptionType.FeedbackSize = 128; в моем примере выше, и я получаю CryptographicExecption:

System.Security.Cryptography.CryptographicException не было обработано
  Сообщение = "Плохие данные. \ R \n"
  Источник ="System.Core"
  Трассировки стека:
       в System.Security.Cryptography.CapiNative.SetKeyParameter(ключ SafeCapiKeyHandle, параметр KeyParameter, значение Byte[])
       в System.Security.Cryptography.CapiNative.SetKeyParameter(ключ SafeCapiKeyHandle, параметр KeyParameter, значение Int32)
       в System.Security.Cryptography.CapiSymmetricAlgorithm.SetupKey(ключ SafeCapiKeyHandle, Byte[] iv, CipherMode cipherMode, Int32 feedbackSize)
       в System.Security.Cryptography.CapiSymmetricAlgorithm..ctor(Int32 blockSize, Int32 feedbackSize, поставщик SafeCspHandle, ключ SafeCapiKeyHandle, Byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, EncryptionMode encryptionMode)
       в System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(ключ SafeCapiKeyHandle, байт [] iv)
       в System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(ключ Byte[], Byte[] iv)
       в AESTest.Form1.Encrypt(Byte[] unencryptedData) в C:\Documents and Settings\nschoonmaker\ Мои документы \Visual Studio 2005\Projects\AESTest\AESTest\Form1.cs: строка 79
       в AESTest.Form1..ctor() в C:\Documents and Settings\nschoonmaker\ Мои документы \Visual Studio 2005\Projects\AESTest\AESTest\Form1.cs: строка 73
       в AESTest.Program.Main() в C:\Documents and Settings\nschoonmaker\ Мои документы \Visual Studio 2005\Projects\AESTest\AESTest\Program.cs: строка 17

Что-то не так с dll System.Core, который бы не поддерживал это, или мне нужно что-то изменить?

С другой стороны, если я изменю размер FeedbackSize на 8 для обоих, это похоже на работу! Даже для режима CFB. Итак, я думаю, что мой следующий вопрос: как мне заставить работать 128 (и, надеюсь, это положит конец этому вопросу)?

Другие вопросы по тегам