CFB模式下的TripleDES,C#和Crypto ++有所不同

这是我的问题:我有一个C ++中的遗留代码(使用crypto ++ v5.6.1),我在C#中开发了一个新代码(使用System.Security.Cryptography的.NET 3.5)。 我无法更改 C ++代码,但我需要能够解密先前加密的数据,以前的应用程序必须能够解密我将使用新的C#代码加密的数据。

在两种情况下使用的算法都是具有CFB密码模式的TripleDES,但最后,加密数据不相同,字节数和第一个字节相同,但除此之外所有其他字节都不同。

在C ++代码中手动完成填充(添加零)。 所以我将PaddingValue设置为PaddingMode.Zeros。 (我也尝试在C#代码中手动添加零,它没有改变任何东西)。

我尝试使用不同的System.Text.Encoding但结果是相同的(实际上测试的字符是“纯”ASCII(即:在0和126之间))。

在C ++代码中,MandatoryBlockSize()的值是8,所以我也将FeedbackSize设置为8。 但是,如果我理解它写,它实际上是我的IV的大小,不是吗?

密钥大小为24个字节(3个不同的密钥),IV为8个字节长。 它们在2个代码中都是相同的。

如果我在两种情况下都使用CBC模式,结果是相同的(但是,正如我所说,我无法更改遗留代码…),OFB和CTS模式抛出exception(一个不可用,另一个不兼容)在我的.NET应用程序上,所以我无法比较结果。

我尝试使用Mono,.Net版本3.5和4.0,或使用visual,与.Net 3.5或4.0,4加密结果相同,但它与原始结果不同。

现在我真的不知道要测试什么…我宁愿不在C ++ / CLI项目中包装Crypto ++来使用它而不是System.Security.Cryptography。

有人有建议或者能说出我做错了什么吗?

这是C ++代码:

void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv) { byte *bIn; byte *bOut; LONG l2,lb; CFB_FIPS_Mode::Encryption encryption_DES_EDE3_CFB; encryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); lb = encryption_DES_EDE3_CFB.MandatoryBlockSize(); l2 = ((lIn + lb - 1)/lb)*lb; bIn = (byte*)malloc(l2); bOut = (byte*)malloc(l2); memset(bIn,0,l2); memset(bOut,0,l2); memcpy(bIn,bDataIn,lIn); encryption_DES_EDE3_CFB.ProcessString(bOut, bIn, l2); *lOut = l2; return bOut; } 

这是C#代码:

 public FibxCrypt() { _cryptoAlgo = new TripleDESCryptoServiceProvider(); //_cryptoAlgo.GenerateKey(); _cryptoAlgo.Key = _key; //_cryptoAlgo.GenerateIV(); _cryptoAlgo.IV = _iv; _cryptoAlgo.Mode = CipherMode.CFB; _cryptoAlgo.Padding = PaddingMode.Zeros; _encoding = new UTF8Encoding(); } private MemoryStream EncryptingString(string plainText, out long encryptSize) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); // Create a decrytor to perform the stream transform. ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor(); // Create the streams used for encryption. //using (MemoryStream msEncrypt = new MemoryStream()) MemoryStream msEncrypt = new MemoryStream(); encryptSize = ((plainText.Length + _cryptoAlgo.FeedbackSize - 1) / _cryptoAlgo.FeedbackSize) * _cryptoAlgo.FeedbackSize; using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt, _encoding)) { //Write all data to the stream. swEncrypt.Write(plainText); } } // Return the encrypted memory stream. return msEncrypt; } 

编辑:我试图直接使用加密,而不是使用流,我有同样的问题。

 private MemoryStream EncryptingString(string plainText, out long encryptSize) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor(); byte[] cipherData = encryptor.TransformFinalBlock( _encoding.GetBytes(plainText), 0, plainText.Length); // Return the encrypted memory stream. return msEncrypt; } 

您已更改的FeedBackSize与CFB操作模式( msdn文档 )有关。 因此,您还应该检查C ++和C#中的反馈大小是否相同。

我相信你的bug可能是C ++代码和C#代码之间的恶意BlockSizes。 您是否尝试在C#实现中设置BlockSize = 8?

这些都不正确:

 CFB_FIPS_Mode::Encryption enc; enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); 

sizeof(key)sizeof(iv)返回指针的大小,而不是安全参数的大小。 你应该使用它:

 enc.SetKeyWithIV(key, DES_EDE3::DEFAULT_KEYLENGTH, iv, DES_EDE3::BLOCKSIZE); 

如果它适用于.Net,那么你应该更喜欢增加像Mcrypt和.Net这样的库的反馈大小; 而不是减少Crypto ++中的反馈大小。 这是因为当反馈大小不是完整的块大小时,某些模式会失去安全性。

我不知道这是否适用于.Net,但它应该考虑或尝试:

 public FibxCrypt() { _cryptoAlgo = new TripleDESCryptoServiceProvider(); _cryptoAlgo.Key = _key; _cryptoAlgo.IV = _iv; _cryptoAlgo.Mode = CipherMode.CFB; _cryptoAlgo.Padding = PaddingMode.Zeros; // Add this: _cryptoAlgo.FeedbackSize = _cryptoAlgo.BlockSize; } 

如果您无法在.Net中调整反馈大小,那么这里是如何在Crypto ++中更改反馈大小。 您设置AlgorithmParameters以保存反馈大小参数,然后使用其他参数调用SetKey

 void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv) { AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/) (Name::IV(), ConstByteArrayParameter(iv, DES_EDE3::BLOCKSIZE)); CFB_FIPS_Mode::Encryption enc; enc.SetKey(key, 24, DES_EDE3::DEFAULT_KEYLENGTH); ... } 

我不清楚在FIPS模式下运行的CFB模式是否允许这么小的反馈大小。 如果它抛出exception,那么您将只需要使用CFB_Mode

由于operator()重载, AlgorithmParameters看起来有点奇怪。 您可以在Crypto ++ wiki上的NameValuePairs上阅读它。 其他感兴趣的维基页面是TripleDES和CFB Mode 。

—-

另外需要注意的是文本编码。 由于UTF-16,它通常会导致.Net和Java中的互操作性问题。 UTF-8和ASCII导致的问题最少。 你应该没问题,因为你encoding = new UTF8Encoding()

但是如果事情仍然不适合你,那么你就是一个未编码或解释的字节消息。 例如,在.Net和Crypto ++中使用它:

 byte msg[4] = { 0x01, 0x02, 0x03, 0x04 }; 

不解释这四个字节,因此它会对步骤进行编码。