I am trying to use the same key and VI to encrypt and decryp the same message, say aabbcc@gmail.com
. The key length is 128 bit as I know that in Java/Android, 256 is not easy to implement.
Here is my function to do the AES encryption using Crypto++
string encryptString(string toBeEncrypted) {
//
// Create Cipher Text
//
CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
std::string ciphertext;
std::cout << "To be encrypted (" << toBeEncrypted.size() << " bytes)" << std::endl;
std::cout << toBeEncrypted;
std::cout << std::endl << std::endl;
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(ciphertext), CryptoPP::StreamTransformationFilter::PKCS_PADDING);
stfEncryptor.Put(reinterpret_cast<const unsigned char*> (toBeEncrypted.c_str()), toBeEncrypted.length() + 1);
stfEncryptor.MessageEnd();
}
key is "4ff539a893fed04840749287bb3e4152" and IV is "79f564e83be16711759ac7c730072bd0".
They are stored in binary in a ubuntu running in VMWare on a x86 Windows.
The function to convert key
and iv
from byte to hex array is:
std::string hexToStr(unsigned char *data, int len)
{
std::stringstream ss;
ss<<std::hex;
for(int i(0);i<len;++i){
ss<<std::setfill('0')<<std::setw(2)<<(int)data[i];
}
return ss.str();
}
I checked the hex string vs the memory of byte array key
and iv
, and they are matching.
The results for encrypting aabbcc@gmail.com
is c08a50b45ff16650542e290e05390a6c6fe533e11e9f802ad7d47681fd41f964
from C++.
I obtained this by passing the returned string ciphertext
into the function hexToStr
like cout<<TFFHelper::hexStr((unsigned char *)ciphertext.c_str(), ciphertext.length())<<endl;
I can also decrpt it with the following function, and I passed the raw string rather than the hex string into this function.
string TFFEncryption::decryptString(string toBeDecrypted) {
string decryptedtext;
CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decryptedtext), CryptoPP::StreamTransformationFilter::PKCS_PADDING);
stfDecryptor.Put(reinterpret_cast<const unsigned char*> (toBeDecrypted.c_str()), toBeDecrypted.size());
stfDecryptor.MessageEnd();
return decryptedtext;
}
I put the same VI and KEY in my Android code, and try to encrypt. It ends up in a half matching results after encrypting.
Android code is as follow:
public class myAES {
private static final String key = "4ff539a893fed04840749287bb3e4152";
private static final String initVector = "79f564e83be16711759ac7c730072bd0";
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(initVector));
SecretKeySpec skeySpec = new SecretKeySpec(hexStringToByteArray(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
Log.v("Encryption successful", bytesToHex(encrypted));
return encrypted;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(byte[] encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(initVector));
SecretKeySpec skeySpec = new SecretKeySpec(hexStringToByteArray(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(encrypted);
Log.v("Decryption successful", new String(original, "UTF-8"));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
I got the result of C08A50B45FF16650542E290E05390A6CFE5466FC480F0667517B248410930B69
.
I used the same piece of code in Netbeans on Java8, running on the same Ubuntu of the C++ code, and got exactly the same results as what I mentioned on the previous line (Android results). I don't think this is OS dependent, but probably I did something wrong with either Java or C++ in my code.
So the first half of the hex strings are matching, and the later half is not. I tried to reduced the phrase aabbcc@gmail.com
into abc@gmail.com
, which results in complete different results from C++ vs Java (Ubuntu vs Android).
However, if I decrpt that binary array in Java, I got the original phrase aabbcc@gmail.com
or abc@gmail.com
.
I have the following questions.
const char *
into unsigned char *
? I think it should be OK as I am getting the hex string of the binaryThe email in the Crypto++ message is '0'
terminated, but the message in Java is not.
As AES is a block cipher with a block length of 128 bits (16 bytes), and your email is exactly 16 bytes long, the first block gets encrypted the same way in both implementations. The '0'
in the first position of the second block gives the difference in the second block of the encryption.
Notice the extra '00'
in below screenshot using this online tool. All the '0f'
following the '00'
is the PKCS5 Padding that this tool did not remove here ..