为什么 RijndaelManaged 和 AesCryptoServiceProvider 返回不同的结果? [英] Why are RijndaelManaged and AesCryptoServiceProvider returning different results?

查看:30
本文介绍了为什么 RijndaelManaged 和 AesCryptoServiceProvider 返回不同的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我运行的示例.它具有相同的 Mode、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

这是我用来生成这些结果的代码

<前><代码>公共部分类 AesTest{私有对称算法 mEncryptionType;私人字节[] mPrivateKey;私有字节[] mInitializationVector;私有字节[] mData;公共 AesTest(){mPrivateKey = 新字节[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 = 新字节[16]{0x33, 0x33, 0x33, 0x33,0x33, 0x33, 0x33, 0x33,0x33, 0x33, 0x33, 0x33,0x33、0x33、0x33、0x33};mData = 新字节[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;字节[] rij_encrypted_data = 加密(mData);mEncryptionType = new AesCryptoServiceProvider();mEncryptionType.Mode = CipherMode.CFB;mEncryptionType.Padding = PaddingMode.PKCS7;mEncryptionType.BlockSize = 128;mEncryptionType.KeySize = 256;byte[] aes_encrypted_data = Encrypt(mData);}公共虚拟字节 [] 加密(字节 [] 未加密数据){返回 TransformData(unencryptedData, mEncryptionType.CreateEncryptor(mPrivateKey, mInitializationVector));}私有字节[] TransformData(byte[] dataToTransform, ICryptoTransform cryptoTransform){字节 [] 结果 = 新字节 [0];if (dataToTransform != null && cryptoTransform != null && dataToTransform.Length > 0){//创建内存流来存储结果MemoryStream mem_stream = new MemoryStream();//创建加密流以进行转换CryptoStream crypto_stream = new CryptoStream(mem_stream, cryptoTransform, CryptoStreamMode.Write);//字节在写入时被转换crypto_stream.Write(dataToTransform, 0, dataToTransform.Length);//刷新最后一个块crypto_stream.FlushFinalBlock();//将转换后的内存流转换回字节数组结果 = mem_stream.ToArray();//关闭流mem_stream.Close();crypto_stream.Close();}返回结果;}}

我想我只是想知道我是否错过了什么.

更新: 原来 AesManaged 将抛出 CryptographicException(指定的密码模式对该算法无效").我觉得 AesCryptoServiceProvider 也应该这样做,但它没有.FIPS 认证类允许无效的密码模式,这似乎很有趣.

解决方案

来自 Microsoft 的回应:

RijndaelManaged 类和AesCryptoServiceProvider 类是两个不同的实现.RijndaelManaged 类是一种Rijndael 算法的实现在 .net 框架中,这不是在 NIST(国家标准标准与技术研究所)加密模块验证计划(CMVP).

然而,AesCryptoServiceProvider 类调用Windows Crypto API,它使用RSAENH.DLL,并已通过验证CMVP 中的 NIST.虽然瑞恩达尔算法是 NIST 的赢家算法选择竞赛那将成为AES,有一些Rijndael 和官方 AES.所以,RijndaelManaged 类和AesCryptoServiceProvider 类有实现上的细微差别.

另外,RijndaelManaged 类不能提供等价物AES 实现.有在 .net 中实现的另一个类框架,AesManaged 类.这类刚刚包装 RijndaelManaged具有固定块大小的类和达到AES的迭代次数标准.但是,它不支持反馈大小,尤其是当模式设置为 CFB 或 OFB,CryptographicException 将被抛出.

更多信息请参考以下 MSDN 文档.

AesManaged ClassAesManaged.Mode 属性

如果您想选择标准 AES 作为您的安全算法应用程序,我们建议使用AesCryptoServiceProvider 类.如果你想要混合 RijndaelManged 类和 AesCryptoServiceProvider 类您的申请,我们建议使用 CBC模式而不是 CFB 模式计划实施以来两个班级的 CBC 模式是一样.

Here is the example that I have run. It has the same Mode, Padding, BlockSize, KeySize. I am using the same init vector, key and data.

Using the RijndaelManaged produces an encrypted value of: 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

Using the AesCryptoServiceProvider produces an encrypted value of: 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

Here is the code I used to generate these results


   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;
      }
   }

I guess I'm just wondering if I missed something.

Update: Turns out that AesManaged will throw a CryptographicException ("The specified cipher mode is not valid for this algorithm") if you try and set the CipherMode to CFB. I feel that the AesCryptoServiceProvider should do that same, but it doesnt. Seems funny that the FIPS Certified class allows invalid cipher modes.

解决方案

Response from Microsoft:

RijndaelManaged class and AesCryptoServiceProvider class are two different implementations. RijndaelManaged class is a kind of implementation of Rijndael algorithm in .net framework, which was not validated under NIST (National Institute of Standards and Technology) Cryptographic Module Validation Program (CMVP).

However, AesCryptoServiceProvider class calls the Windows Crypto API, which uses RSAENH.DLL, and has been validated by NIST in CMVP. Although Rijndael algorithm was the winner of the NIST competition to select the algorithm that would become AES, there are some differences between Rijndael and official AES. Therefore, RijndaelManaged class and AesCryptoServiceProvider class have subtle differences on implementation.

In addition, RijndaelManaged class cannot provide an equivalent implementation with AES. There is another class implemented in .net framework, AesManaged class. This class just wrapped RijndaelManaged class with a fixed block size and iteration count to achieve the AES standard. However, it does not support the feedback size, especially, when the mode is set as CFB or OFB, the CryptographicException will be thrown.

For more information, please refer to the following MSDN documents.

AesManaged Class and AesManaged.Mode Property

If you want to pick up standard AES as security algorithm in your application, we recommend using the AesCryptoServiceProvider class. If you want to mix the RijndaelManged class and AesCryptoServiceProvider class in your application, we suggest using CBC mode instead of CFB mode in your program, since the implementation of the CBC mode in both classes is the same.

这篇关于为什么 RijndaelManaged 和 AesCryptoServiceProvider 返回不同的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆