I'm trying to match encryption schemes on c++ using crypto++ and c# and can't seem to get the same results on both. They both work on them selves, but not from one to the other. Any help would be great!
C++ code using Crypto++:
std::string key = "01286567891233460123456789123456";
std::string iv = "0123456789123456";
std::string encrypt(const std::string& str_in)
{
std::string str_out;
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
return str_out;
}
std::string decrypt(const std::string& cipher_text)
{
std::string str_out;
CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (byte*)iv.c_str());
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(str_out));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher_text.c_str()), cipher_text.size());
stfDecryptor.MessageEnd();
return str_out;
}
The Code Ran:
std::string str = encrypt("123456789012345");
str = decrypt(str);
This output is:
Encrypted: Ö&qcƒ“¹yLY»Lïv¹w“¼LLŠÀ¶ó¢,óð9·
Length: 32
Decrypted: 123456789012345
Length: 16
Now in C#, I have the following code:
public string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
// encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01234567891234560123456789123456");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
}
}
return clearText; //Return the encrypted command
}
public string Decrypt(string cipherText)
{
byte[] clearBytes = Encoding.Default.GetBytes(cipherText);
using (Aes decryptor = Aes.Create("AES"))
{
// decryptor.BlockSize = 128;
decryptor.Padding = PaddingMode.Zeros;
decryptor.KeySize = 128;
decryptor.Mode = CipherMode.CBC;
decryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
decryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
cipherText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
}
}
return cipherText; //Return the decrypted text
}
}
The code ran:
string orig = "123456789012345";
string cipher = Encrypt(orig);
string dedata = Decrypt(cipher);
The results are:
Orig: 123456789012345
Encrypted: êßyoº0¦ëì›X˜Ü
Length: 16
Decrypted: 123456789012345
Length: 16
As you can see, the encrypted strings end up being different. So when I take an encrypted string in c++, it can't decrypt it in c#, as shown here:
bytes[] encryptedText = ENCRYPTED TEXT FROM C++
text = System.Text.Encoding.Default.GetString(encryptedText);
text = Decrypt(text);
The c++ returns 32 bytes for it's encrypted string which I believe is the padding being added. Not sure how to replicate this in the c# code or vise versa to match things up. Not sure if there is something else I'm missing here... Thanks for any help!
EDIT:
I've matched the keys and now the string matches on both ends except for the padding difference. When I try to decrypt the string in C# it tells me the input data is not the correct block size? Any help with this now?
EDIT AGAIN:
It seems to be generating the same byte string for each c# and c++ encryption function, so that problem is resolved. The problem I now seem to have is on the c# side, I receive the encrypted string and convert the bytes using: text = System.Text.Encoding.Default.GetString(recvBuf); recvBuf being the encrypted string from c++ and it's missing the last character of the string. It matches up with the c++ string minus the last char?? Not sure why this is happening.
For example, my c++ sends over this encrypted string: Ö&qcƒ“¹yLY»Lïv and my c# program will only receive this: Ö&qcƒ“¹yLY»Lï which in turn will make it fail at decryptng. The encrypted string is being sent over a TCP SOCKET if that makes any difference.
EDIT
Still missing bytes after changing encoding and decoding to base64 on both ends.
C++ 1iZxY4OTHrl5TFm7Gkzvdrl3k7xMTIrAtvOiLPPwObc=
C# 1iZxY4OTHrl5TFm7Gkzvdg==
C# RECEIVED 1iZxY4OTHrl5TFm
New Code C#:
public string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
// encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Convert.ToBase64String(bt);
}
}
return clearText; //Return the encrypted command
}
And C++ Code:
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
str_out2 = base64_encode(reinterpret_cast<const unsigned char*>(str_out.c_str()), strlen(str_out.c_str()));
return str_out2;
}
EDIT
IT WORKS!!! It was simply an overlook on my part, my socket was checking the size of the data before encrypted and sending that size instead of the encrypted string size. Fix that and all it working perfect. Thanks Brandon for the help!