Почему 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 должен делать то же самое, но это не так. Кажется забавным, что класс FIPS Certified допускает неправильные режимы шифрования.
Ответы
Ответ 1
Ответ от Microsoft:
RijndaelManaged
класс и
Класс AesCryptoServiceProvider
- два
различные реализации.
RijndaelManaged
класс - это своего рода
реализация алгоритма Рийндаля
в .net framework, который не был
подтверждено в соответствии с NIST (National
Институт стандартов и технологий)
Проверка криптографического модуля
Программа (CMVP).
Однако,
AesCryptoServiceProvider
вызовы класса
API Windows Crypto, который использует
RSAENH.DLL, и был подтвержден
NIST в CMVP. Хотя Rijndael
Алгоритм был победителем NIST
конкурс на выбор алгоритма
это будет AES, есть некоторые
различия между Rijndael и
официальный AES. Следовательно,
RijndaelManaged класс и
Класс AesCryptoServiceProvider
имеет
тонкие различия в реализации.
Кроме того, класс RijndaelManaged
не может обеспечить эквивалент
реализации с AES. Там есть
другой класс, реализованный в .net
framework, AesManaged
. Эта
класс, только что завернутый RijndaelManaged
класс с фиксированным размером блока и
количество итераций для достижения AES
стандарт. Однако он не поддерживает
размер обратной связи, особенно, когда
режим установлен как CFB или OFB,
CryptographicException
будет сброшен.
Для получения дополнительной информации см.
следующие документы MSDN.
AesManaged Class и Свойство AesManaged.Mode
Если вы хотите забрать стандартную AES как
алгоритм безопасности в вашем
приложения, мы рекомендуем использовать
AesCryptoServiceProvider
. если ты
хотите смешать класс RijndaelManged
и AesCryptoServiceProvider
в
ваше приложение, мы предлагаем использовать CBC
вместо режима CFB в вашем
программы, поскольку осуществление
режим CBC в обоих классах
то же самое.
Ответ 2
Я думаю, что это связано с CipherMode.CFB. См. этот пост, описывающий AesManaged:
AesManaged на самом деле просто оболочка вокруг Rinjdael Управляемый с помощью некоторого кода добавлен, чтобы убедиться, что вы не настроить алгоритм для работы в не-AES-совместимый способ. Например, AesManaged не позволяет вам измените размер блока. (Он также будет запретить использование режимов CFB и OFB из-за того, что RijndaelManaged работает с теми режимы).
Обратите внимание, что если вы используете CipherMode.ECB или CipherMode.CBC, вы увидите идентичные результаты. Любая причина, по которой вам нужен CFB, а не CBC?
Ответ 3
Информация о добавлении из этот пост говорит:
По сути, если вы хотите использовать RijndaelManaged как AES, вам необходимо убедиться, что:
1) Размер блока равен 128 бит
2) Вы не используете режим CFB, или если вы размер обратной связи также составляет 128 бит
Хорошо, отлично. Я добавил mEncryptionType.FeedbackSize = 128; к моему приведенному выше примеру, и я получаю CryptographicExecption:
System.Security.Cryptography.CryptographicException was unhandled
Message="Bad Data.\r\n"
Source="System.Core"
StackTrace:
at System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, Byte[] value)
at System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, Int32 value)
at System.Security.Cryptography.CapiSymmetricAlgorithm.SetupKey(SafeCapiKeyHandle key, Byte[] iv, CipherMode cipherMode, Int32 feedbackSize)
at System.Security.Cryptography.CapiSymmetricAlgorithm..ctor(Int32 blockSize, Int32 feedbackSize, SafeCspHandle provider, SafeCapiKeyHandle key, Byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, EncryptionMode encryptionMode)
at System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(SafeCapiKeyHandle key, Byte[] iv)
at System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(Byte[] key, Byte[] iv)
at AESTest.Form1.Encrypt(Byte[] unencryptedData) in C:\Documents and Settings\nschoonmaker\My Documents\Visual Studio 2005\Projects\AESTest\AESTest\Form1.cs:line 79
at AESTest.Form1..ctor() in C:\Documents and Settings\nschoonmaker\My Documents\Visual Studio 2005\Projects\AESTest\AESTest\Form1.cs:line 73
at AESTest.Program.Main() in C:\Documents and Settings\nschoonmaker\My Documents\Visual Studio 2005\Projects\AESTest\AESTest\Program.cs:line 17
Что-то не так с dll System.Core, которое не поддерживает это, или мне нужно что-то изменить?
С другой стороны, если я изменил значение FeedbackSize на 8 для обоих, это, похоже, сработает! Даже для режима CFB. Поэтому я предполагаю, что мой следующий вопрос: как мне заставить работать 128 (и, надеюсь, это положит конец этому вопросу)?