Вопрос по java, encryption, android, aes, base64 – не расшифровывать то, что я зашифровал

1

У меня странная проблема ...

Основываясь на моем решенииРасшифровка жестко закодированного файла как байта []

Итак, я написал небольшой класс Cypher, чтобы помочь с шифрованием / дешифрованием ... Он имел обыкновение макетировать ключ, жестко закодированный в каком-то месте, и другой предварительно зашифрованный ключ, хранящийся в другом месте. Но это несколько неуместно.

процесс шифрования шел так:

retrieve the hardcoded byte array use it to decrypt key2 use key2 to decrypt data use key1 to further decrypt data have decrypted data

Я хранил зашифрованные данные в виде шестнадцатеричной строки, используя эти две функции, чтобы получить оттуда

private static String byteArrayToHexString(byte[] b)
{
    StringBuffer sb = new StringBuffer(b.length * 2);
    for (int i = 0; i < b.length; i++)
    {
        int v = b[i] & 0xff;
        if (v < 16)
        {
            sb.append('0');
        }
        sb.append(Integer.toHexString(v));
    }
    return sb.toString().toUpperCase();
}

private static byte[] hexStringToByteArray(String s)
{
    byte[] b = new byte[s.length() / 2];
    for (int i = 0; i < b.length; i++)
    {
        int index = i * 2;
        int v = Integer.parseInt(s.substring(index, index + 2), 16); //THIS LINE
        b[i] = (byte) v;
    }
    return b;
}

Это сработало безупречно; на самом деле это сработало настолько хорошо, что я реализовал это в своем реальном проекте. Проект не удалось запустить из-за того, что я не проверил его полностью.

Оказывается, он зашифровывает / дешифрует почти все файлы, кроме одного, который не требуется расшифровывать.

Однако я точно определил проблему - ЭТА строка выдает исключение IllegalNumberFormat; в какой-то момент я познакомился с этимhttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 также. Я бы и мог вернуться к этому методу, если бы кто-то описал способ обойти случай, когда строка длиной 2 преобразуется в четыре байта, которые выбрасывают исключение IllegalNumberFormatException.

Итак, я решил, что, поскольку я не могу декодировать файл (и, очевидно, не могу поделиться им здесь, чтобы вы, ребята, могли его попробовать), мне нужно было каким-то образом преобразовать его, чтобы сделать его безопасным для транспортировки. Введите класс Base64Coder, который кодирует в строки base64 ...

Это, казалось, ввело новую проблему - заполнение истощалось.

Вопрос прост - что я делаю не так? Мне нужно соответствовать этим данным, и он должен уметь шифровать / дешифровать правильно и одинаково. Мне бы хотелось предложение о наиболее легком из возможных решений с наименьшим количеством копий / вставок ... псевдокод здесь не сработает.

Вот что я делаю сейчас ...

public static char[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(true);
    System.err.println("encrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters());
    byte[] encrypted = cipher.doFinal(value);

    SecretKeySpec key2 = getSecretKeySpec(false);
    cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.ENCRYPT_MODE, key2, cipher.getParameters());
    byte[] encrypted2 = cipher.doFinal(encrypted);

    return Base64Coder.encode(encrypted2);
}

public static byte[] decrypt2(char[] message) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(false);
    System.err.println("decrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.DECRYPT_MODE, key1);
    byte[] decrypted = cipher.doFinal(Base64Coder.decode(message));

    SecretKeySpec key2 = getSecretKeySpec(true);
    cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.DECRYPT_MODE, key2);
    byte[] decrypted2 = cipher.doFinal(decrypted);

    return decrypted2;
}

Обратите внимание, что ключи в настоящее время полностью открыты (жестко закодированы) для целей тестирования.

Вот мой тест-кейс

public static void main(String... args) throws Exception
{
    //      byte[] data = "hello".getBytes();
    File PEM = new File(PATH_TO_FILES + SOURCE_PEM);
    File DER = new File(PATH_TO_FILES + SOURCE_DER);
    File cryptoPEM = new File(PATH_TO_FILES + "cryptopem");
    File cryptoDER = new File(PATH_TO_FILES + "cryptoder");

    byte[] cryptokey = encryptA(ASSET_KEY);
    System.out.println(new String(cryptokey));

    //pem key
    System.out.println("PEM");
    byte[] data = getBytesFromFile(PEM);
    char[] crypted = encrypt2(data);
    //      FileOutputStream fos = new FileOutputStream(cryptoPEM);
    FileWriter fw = new FileWriter(cryptoPEM);
    fw.write(crypted);
    fw.flush();

    //der key
    System.out.println("DER");
    data = getBytesFromFile(DER);
    crypted = encrypt2(data);
    fw = new FileWriter(cryptoDER);
    fw.write(crypted);
    fw.flush();

    //opentext
    System.out.println("checking PEM...");
    crypted = Base64Coder.encode(getBytesFromFile(cryptoPEM));
    byte[] decrypted = decrypt2(crypted,  false);
    byte[] decryptedData = decrypted;

    if (!Arrays.equals(getBytesFromFile(PEM), decryptedData)) { throw new Exception("PEM Data was not decrypted successfully"); }

    System.out.println("checking DER...");
    crypted = Base64Coder.encode(getBytesFromFile(cryptoDER));
    decrypted = decrypt2(crypted,  false);
    decryptedData = decrypted;

    if (!Arrays.equals(getBytesFromFile(DER), decryptedData)) { throw new Exception("DER Data was not decrypted successfully"); }
}

И сейчас я получаю InvalidBlockSizeException .... Пожалуйста, кто-то пролил некоторый свет на это, я просто хочу, чтобы это сработало ...

Замена "key2" для последующего использования IV в «AES / CBC / PKCS5Padding»; вариант, который я сейчас рассматриваю. По сути, ничего не изменится, кроме второго шага шифрования. Теоретически и методически я бы оставил все как есть - если, конечно, не будет описано лучшее решение.

В заключение я хотел бы отметить, что это вопрос программиста, а не вопроса студента по ИТ-безопасности, поэтому правильный код ценится больше, чем теоретический ответ, охватывающий маловероятные крайние случаи.

РЕДАКТИРОВАТЬ: ну, я не могу дать вам числа, которые вызывают исключение IllegalNumberFormatExmat, потому что я потерял код с этого утра. Кажется, я не могу воспроизвести проблему, так что я думаю, пытаясь понять, что эта часть бесполезна.

Вот результат теста образца:

encrypt():  [email protected]
[email protected]��_׵G�j��!�c;D�i�lR?z�j\
PEM
encrypt():  [email protected]
DER
encrypt():  [email protected]
checking PEM...
decrypt():  javax.crypto.spec.[email protected]
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

что означает, что Base64 вроде как все испортил ...

Каково входное значение вInteger.parseInt() за что выкидывает исключение? Одно это не должно содержать никакой секретной информации, но было бы очень полезно для помощи вам. Joachim Sauer
По моим расчетам, [47, -61, -67, -65] это [2F C3 BD BF]. Предполагая, что это UTF-8, то есть "/"; сопровождаемый U + 3F7F, который является китайским символом. Насколько вы уверены в входе в систему? Если это произойдет в конце, это может быть проблемой заполнения. rossum
Да, у меня нет проблем с раскрытием этой информации. В какой-то момент он встречается на отмеченной линии (как вы можете видеть, для этого нужно две шестнадцатеричные буквы), пока не попадет в эти байты (две буквы) - 0 * с байтами [47, -61, -67, -65] Я обновлю свой ответ, когда поймаю их снова, как я уже сказал, - я могу вернуться назад. Shark
Вы пробовали Byte.parseByte (stringRepresentationOfByte, 16) вместо Integer.parseInt (...)? Buhb
Buhb, вы не читали мой пост - я ссылался на известную проблему в Java, которая не в состоянии проанализировать мой ввод, потому что байты подписаны. Вот почему я использовал Integer.parseInt (), но он также не работает, потому что он встречает символ длиной более одного байта. Я также пытался использовать getBytes ("UTF-8"), но безрезультатно. Я действительно много чего перепробовал, но ни одна из них не сработала ... Вот почему я написал здесь, чтобы узнать, можно ли что-нибудь спасти или просто переписать всю эту чертову вещь с нуля в надежде, что я не совершу ту же ошибку : // Shark

Ваш Ответ

3   ответа
1

//opentext
System.out.println("checking PEM...");
crypted = Base64Coder.encode(getBytesFromFile(cryptoPEM));

Ранее вы написалиchar[] в файл, но теперь вы читаетеbyte[] из файла и перекодировки в base64. Содержимое файла уже должно быть в кодировке base64!

Вам нужна новая функция getCharsFromFile, которая возвращает char [] или String и передает ее непосредственно в decrypt2.

Когда я использую FileReader, который читает char [], я получаю исключение заполнения. Shark
0

аботать.

public static byte[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(true);
    System.err.println("encrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters());
    byte[] encrypted = cipher.doFinal(value);

    SecretKeySpec key2 = getSecretKeySpec(false);
    System.err.println("encrypt():\t" + key2.toString());
    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key2, new IvParameterSpec(getIV()));
    byte[] encrypted2 = cipher.doFinal(encrypted);

    return encrypted2;//Base64Coder.encode(encrypted2);
}

public static byte[] decrypt2(byte[] message, boolean A) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(false);
    System.err.println("decrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, key1, new IvParameterSpec(getIV()));
    byte[] decrypted = cipher.doFinal(message);

    SecretKeySpec key2 = getSecretKeySpec(true);
    System.err.println("decrypt():\t" + key2.toString());
    cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, key2);
    byte[] decrypted2 = cipher.doFinal(decrypted);

    return decrypted2;
}
0
Почему я должен? Я не думаю, что это base64, который его усиливает. но это может быть Shark

Похожие вопросы