这是我的问题:我在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模式在我的.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<DES_EDE3>::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;
}
答案 0 :(得分:1)
您已更改的FeedBackSize与CFB操作模式(msdn documentation)有关。因此,您还应该检查C ++和C#中的反馈大小是否相同。
我相信您的错误可能是C ++代码和C#代码之间的恶意BlockSizes。您是否尝试在C#实现中设置BlockSize = 8?
答案 1 :(得分:1)
这些不正确:
CFB_FIPS_Mode<DES_EDE3>::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<DES_EDE3>::Encryption enc;
enc.SetKey(key, 24, DES_EDE3::DEFAULT_KEYLENGTH);
...
}
我不清楚在FIPS模式下运行的CFB模式是否允许这么小的反馈大小。如果它抛出异常,那么您只需使用CFB_Mode
。
AlgorithmParameters
重载, operator()
看起来有点奇怪。您可以在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 };
不解释这四个字节,因此它会对编码问题进行分步。