简体   繁体   English

为什么RijndaelManaged和AesCryptoServiceProvider会返回不同的结果?

[英]Why are RijndaelManaged and AesCryptoServiceProvider returning different results?

Here is the example that I have run. 这是我运行的例子。 It has the same Mode, Padding, BlockSize, KeySize. 它具有相同的Mode,Padding,BlockSize,KeySize。 I am using the same init vector, key and data. 我使用相同的init向量,密钥和数据。

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 使用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

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 使用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

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. 更新:如果您尝试将CipherMode设置为CFB,则原来AesManaged将抛出CryptographicException(“指定的密码模式对此算法无效”)。 I feel that the AesCryptoServiceProvider should do that same, but it doesnt. 我觉得AesCryptoServiceProvider也应该这样做,但它没有。 Seems funny that the FIPS Certified class allows invalid cipher modes. 看起来很有趣FIPS认证课程允许无效的密码模式。

Response from Microsoft: 来自Microsoft的回复:

RijndaelManaged class and AesCryptoServiceProvider class are two different implementations. RijndaelManaged类和AesCryptoServiceProvider类是两种不同的实现。 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). RijndaelManaged类是.net框架中Rijndael算法的一种实现,在NIST(美国国家标准与技术研究院)密码模块验证程序(CMVP)下未经验证。

However, AesCryptoServiceProvider class calls the Windows Crypto API, which uses RSAENH.DLL, and has been validated by NIST in CMVP. 但是, AesCryptoServiceProvider类调用Windows Crypto API,它使用RSAENH.DLL,并已由NIST在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. 尽管Rijndael算法是NIST竞赛中获胜者选择将成为AES的算法,但Rijndael和官方AES之间存在一些差异。 Therefore, RijndaelManaged class and AesCryptoServiceProvider class have subtle differences on implementation. 因此,RijndaelManaged类和AesCryptoServiceProvider类在实现上有细微差别。

In addition, RijndaelManaged class cannot provide an equivalent implementation with AES. 此外, RijndaelManaged类无法提供与AES等效的实现。 There is another class implemented in .net framework, AesManaged class. 在.net框架中实现了另一个类, AesManaged类。 This class just wrapped RijndaelManaged class with a fixed block size and iteration count to achieve the AES standard. 这个类只是用固定的块大小和迭代次数包装RijndaelManaged类来实现AES标准。 However, it does not support the feedback size, especially, when the mode is set as CFB or OFB, the CryptographicException will be thrown. 但是,它不支持反馈大小,尤其是当模式设置为CFB或OFB时,将抛出CryptographicException

For more information, please refer to the following MSDN documents. 有关详细信息,请参阅以下MSDN文档。

AesManaged Class and AesManaged.Mode Property AesManaged类AesManaged.Mode属性

If you want to pick up standard AES as security algorithm in your application, we recommend using the AesCryptoServiceProvider class. 如果要在应用程序中选择标准AES作为安全算法,我们建议使用AesCryptoServiceProvider类。 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. 如果要在应用程序中混合使用RijndaelManged类和AesCryptoServiceProvider类,我们建议在程序中使用CBC模式而不是CFB模式,因为两个类中CBC模式的实现是相同的。

I think it has to do with the CipherMode.CFB. 我认为它与CipherMode.CFB有关。 See this post describing AesManaged : 这篇描述AesManaged的帖子

AesManaged is actually just a wrapper around RinjdaelManaged with some code added to make sure that you do not setup the algorithm to operate in a non-AES compatible way. AesManaged实际上只是RinjdaelManaged的一个包装器,添加了一些代码以确保您不会将算法设置为以非AES兼容的方式运行。 For instance, AesManaged does not allow you to change the block size. 例如,AesManaged不允许您更改块大小。 (It will also disallow the use of CFB and OFB mode because of the way that RijndaelManaged works with those modes). (由于RijndaelManaged使用这些模式的方式,它也将禁止使用CFB和OFB模式)。

Note that if you use CipherMode.ECB or CipherMode.CBC, you'll see identical results. 请注意,如果您使用CipherMode.ECB或CipherMode.CBC,您将看到相同的结果。 Any reason why you need CFB and not CBC? 你需要CFB而不是CBC的任何理由?

Addition information from this post says: 这篇文章的补充信息说:

Essentially, if you want to use RijndaelManaged as AES you need to make sure that: 基本上,如果您想将RijndaelManaged用作AES,您需要确保:
1) The block size is set to 128 bits 1)块大小设置为128位
2) You are not using CFB mode, or if you are the feedback size is also 128 bits 2)您没有使用CFB模式,或者如果您的反馈大小也是128位

Ok, great. 好,很好。 I added mEncryptionType.FeedbackSize = 128; 我添加了mEncryptionType.FeedbackSize = 128; to my above example and I get an CryptographicExecption: 在上面的例子中,我得到了一个CryptographicExecption:

\nSystem.Security.Cryptography.CryptographicException was unhandled System.Security.Cryptography.CryptographicException未处理\n  Message="Bad Data.\\r\\n" 消息=“错误数据。\\ r \\ n”\n  Source="System.Core" 来源= “System.Core程序”\n  StackTrace: 堆栈跟踪:\n       at System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, Byte[] value) 在System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle键,KeyParameter参数,Byte []值)\n       at System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, Int32 value) 在System.Security.Cryptography.CapiNative.SetKeyParameter(SafeCapiKeyHandle键,KeyParameter参数,Int32值)\n       at System.Security.Cryptography.CapiSymmetricAlgorithm.SetupKey(SafeCapiKeyHandle key, Byte[] iv, CipherMode cipherMode, Int32 feedbackSize) 在System.Security.Cryptography.CapiSymmetricAlgorithm.SetupKey(SafeCapiKeyHandle键,Byte [] iv,CipherMode cipherMode,Int32 feedbackSize)\n       at System.Security.Cryptography.CapiSymmetricAlgorithm..ctor(Int32 blockSize, Int32 feedbackSize, SafeCspHandle provider, SafeCapiKeyHandle key, Byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, EncryptionMode encryptionMode) 在System.Security.Cryptography.CapiSymmetricAlgorithm..ctor(Int32 blockSize,Int32 feedbackSize,SafeCspHandle提供程序,SafeCapiKeyHandle键,Byte [] iv,CipherMode cipherMode,PaddingMode paddingMode,EncryptionMode encryptionMode)\n       at System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(SafeCapiKeyHandle key, Byte[] iv) 在System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(SafeCapiKeyHandle key,Byte [] iv)\n       at System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(Byte[] key, Byte[] iv) 在System.Security.Cryptography.AesCryptoServiceProvider.CreateEncryptor(Byte []键,Byte [] iv)\n       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.Encrypt(Byte [] unencryptedData)在C:\\ Documents and Settings \\ nschoonmaker \\ My Documents \\ Visual Studio 2005 \\ Projects \\ AESTest \\ AESTest \\ Form1.cs:第79行\n       at AESTest.Form1..ctor() in C:\\Documents and Settings\\nschoonmaker\\My Documents\\Visual Studio 2005\\Projects\\AESTest\\AESTest\\Form1.cs:line 73 在C:\\ Documents and Settings \\ nschoonmaker \\ My Documents \\ Visual Studio 2005 \\ Projects \\ AESTest \\ AESTest \\ Form1.cs中的AESTest.Form1..ctor():第73行\n       at AESTest.Program.Main() in C:\\Documents and Settings\\nschoonmaker\\My Documents\\Visual Studio 2005\\Projects\\AESTest\\AESTest\\Program.cs:line 17 在C:\\ Documents and Settings \\ nschoonmaker \\ My Documents \\ Visual Studio 2005 \\ Projects \\ AESTest \\ AESTest \\ Program.cs中的AESTest.Program.Main():第17行\n

Is there something wrong with the System.Core dll that wouldnt support this, or do I need to change something else? System.Core dll是否有什么问题不支持这个,或者我是否需要更改其他内容?

On a side note, if I change the FeedbackSize to 8 for both, its seems to work! 另外,如果我将FeedbackSize更改为8,它似乎工作! Even for CFB mode. 即使是CFB模式。 So I guess my next question is, how do I get 128 to work (and hopefully this will put an end to this question)? 所以我想我的下一个问题是,如何让128工作(希望这会结束这个问题)?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM