128-битные зашифрованные результаты Android и Crypto AES не совпадают

#android #c #encryption #crypto #javax.crypto

#Android #c #шифрование #crypto #javax.crypto

Вопрос:

Я пытаюсь использовать один и тот же ключ и 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 на x86 Windows.

Функция для преобразования 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 и КЛЮЧ в свой код 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] amp; 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2   1] = hexArray[v amp; 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 .

У меня есть следующие вопросы.

  1. Что я сделал не так?
  2. Правильно ли вводить регистр const char * unsigned char * ? Я думаю, что все должно быть в порядке, поскольку я получаю шестнадцатеричную строку двоичного файла
  3. Является ли половина совпадающих результатов вызвана заполнением?

Комментарии:

1. Какую версию Crypto вы используете?

2. Crypto обеспечивает HexDecoder . Вы можете использовать его вместо std::string hexToStr(...) , если хотите.

3. apt-cache showpkg libcrypto 9v5 Пакет: libcrypto 9v5 Версии: 5.6.1-9 (/var/ lib/apt/lists/archive.ubuntu.com_ubuntu_dists_xenial_universe_binary-amd64_Packages) (/var/ lib/dpkg/status)

4. Я использовал тот же фрагмент кода в Netbeans на Java8, работающий на том же Ubuntu с кодом C , и получил точно такие же результаты, что и на Android. Я не думаю, что это зависит от ОС, но, вероятно, я сделал что-то не так с Java или C в своем коде.

5. @jww Это HexEncoder , кстати, и возвращает точно такую же шестнадцатеричную строку по сравнению с использованием моей собственной hexToStr .

Ответ №1:

Электронная почта в сообщении Crypto '0' завершается, а сообщение на Java — нет.

Поскольку AES представляет собой блочный шифр с длиной блока 128 бит (16 байт), а длина вашего электронного письма составляет ровно 16 байт, первый блок шифруется одинаково в обеих реализациях. Значение '0' в первой позиции второго блока дает разницу во втором блоке шифрования.

Обратите внимание на лишнее '00' на скриншоте ниже, используя этот онлайн-инструмент. Все '0f' , что следует '00' за дополнением PKCS5, которое этот инструмент здесь не удалил..

введите описание изображения здесь

Комментарии:

1. Я думал, что искушение не было зашифровано … спасибо