Here is my problem: I've got a legacy code in C++ (using crypto++ v5.6.1) and I develop a new one in C# (.NET 3.5 using System.Security.Cryptography). I can't change the C++ code, but I need to be able to decrypt data previously encrypted and previous applications has to be able to decrypt the data I will crypt with my new C# code.
The algorithm used is TripleDES with CFB cipher mode in both cases, but in the end, the encrypted data are not the same, the number of bytes are identical as well as the first byte, but apart from that all other bytes are different.
The padding is manually done (adding zeros) in the C++ code. So I set the PaddingValue to PaddingMode.Zeros. (I also tried to add zeros in the end manually in the C# code, it didn't change anything).
I tried using different System.Text.Encoding but the result is the same (in fact the tested characters are "pure" ASCII (i.e.: between 0 & 126)).
The value of the MandatoryBlockSize(), in the C++ code, is 8, so I set the FeedbackSize to 8 too. But if I understand it write, it is in fact the size of my IV, isn't it ?
The key size is 24 bytes (3 different keys) and the IV is 8 bytes long. They are both the same in the 2 codes.
If I use CBC mode instead in both cases the results are the same (but, as I said, I can't change the legacy code ...), OFB & CTS mode throw exceptions (unavailable for one and incompatible for the other) on my .NET application, so I can't compare results.
I tried using Mono, with .Net versions 3.5 & 4.0, or using visual, with .Net 3.5 or 4.0, and the 4 encrypted results are the same but it differs from the original result.
Now I really don't know what to test ... I'd rather not wrap Crypto++ in a C++/CLI project to use it instead of the System.Security.Cryptography.
Does someone have an advice or can tell what am I doing wrong ?
Here is the C++ code:
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;
}
Here is the C# code:
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;
}
EDIT : I tried to use the Encryptor directly, instead of using the streams and I've got the same problem.
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;
}