Зашифрованные результаты Android и Crypto++ AES 128bit не совпадают
Я пытаюсь использовать один и тот же ключ и VI для шифрования и дешифрования одного и того же сообщения, скажем, aabbcc@gmail.com
, Длина ключа составляет 128 бит, так как я знаю, что в Java/Android 256 нелегко реализовать.
Вот моя функция для шифрования AES с использованием 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();
}
ключ "4ff539a893fed04840749287bb3e4152", а IV "79f564e83be16711759ac7c730072bd0".
Они хранятся в двоичном виде в Ubuntu, работающем в VMWare на Windows x86.
Функция для преобразования key
а также iv
из байта в шестнадцатеричный массив это:
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();
}
Я проверил шестнадцатеричную строку против памяти байтового массива key
а также iv
и они совпадают.
Результаты для шифрования aabbcc@gmail.com
является c08a50b45ff16650542e290e05390a6c6fe533e11e9f802ad7d47681fd41f964
из C++.
Я получил это, передав возвращаемую строку ciphertext
в функцию hexToStr
лайк cout<<TFFHelper::hexStr((unsigned char *)ciphertext.c_str(), ciphertext.length())<<endl;
Я также могу расшифровать его с помощью следующей функции, и я передал в эту функцию необработанную строку, а не шестнадцатеричную строку.
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;
}
Я вставил те же VI и KEY в мой код Android, и попытался зашифровать. Это заканчивается в половине соответствия результатов после шифрования.
Код Android выглядит следующим образом:
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;
}
}
Я получил результат C08A50B45FF16650542E290E05390A6CFE5466FC480F0667517B248410930B69
,
Я использовал тот же кусок кода в Netbeans на Java8, работающий на той же самой Ubuntu кода C++, и получил те же результаты, что и в предыдущей строке (результаты Android). Я не думаю, что это зависит от ОС, но, вероятно, я сделал что-то не так с Java или C++ в моем коде.
Таким образом, первая половина шестнадцатеричных строк совпадает, а вторая половина - нет. Я пытался уменьшить фразу aabbcc@gmail.com
в abc@gmail.com
, что приводит к полному отличным результатам от C++ против Java (Ubuntu против Android).
Однако, если я расшифрую этот двоичный массив в Java, я получу оригинальную фразу aabbcc@gmail.com
или же abc@gmail.com
,
У меня есть следующие вопросы.
- Что я сделал не так?
- Это правильный путь к делу
const char *
вunsigned char *
? Я думаю, что все должно быть в порядке, так как я получаю шестнадцатеричную строку двоичного файла - Половина соответствия результатов вызвана заполнением?
1 ответ
Адрес электронной почты в сообщении Crypto++: '0'
прекращено, но сообщение на Java нет.
Поскольку AES является блочным шифром с длиной блока 128 битов (16 байт), а ваша электронная почта имеет длину ровно 16 байтов, первый блок шифруется одинаково в обеих реализациях. '0'
в первой позиции второй блок дает разницу во втором блоке шифрования.
Обратите внимание на дополнительные '00'
на скриншоте ниже, используя этот онлайн-инструмент. Все '0f'
следуя '00'
это PKCS5 Padding, который этот инструмент не удалил здесь..