Почему 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,0xd0,0xff , 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,0x5a, 0x89,0x31,0xf5 , 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 должен сделать то же самое, но это не так. Кажется забавным, что class FIPS Certified допускает неправильные режимы шифрования.

    Ответ от Microsoft:

    Класс RijndaelManaged и AesCryptoServiceProvider – это две разные реализации. Класс RijndaelManaged – это своего рода реализация алгоритма Rijndael в рамках .net, который не был проверен в рамках программы проверки криптографического модуля NIST (National Institute of Standards and Technology) (CMVP).

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

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

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

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

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

    Я думаю, что это связано с 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, Byte [] iv)
            в System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor (Byte [] key, 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 (и, надеюсь, это положит конец этому вопросу)?

    Давайте будем гением компьютера.