Ручная реализация 3DES (академическая)

Для курса, который я беру, мы вручную реализуем схему 3DES, которая довольно проста на бумаге (два ключа, с шифрованием EDE). Я выбрал Java в качестве языка реализации, но столкнулся с проблемой, связанной с тем, как он обрабатывает шифрование/дешифрование с разными ключами. Я продолжаю получать ошибку javax.crypto.BadPaddingException при попытке применить второй раунд (т.е. «расшифровку» с помощью K2). Шифр DES по умолчанию использует PKCS5Padding, и я предполагаю, что это проблема, но я не уверен, как ее обойти. Мой код для шифрования ниже (надеюсь, он не слишком прямолинейный, меньше я упустил из виду что-то простое). Заранее спасибо.

Ключевое определение (довольно простое, и я постараюсь улучшить его, так как я видел несколько разных подходов при просмотре)

        KeyGenerator kgen = KeyGenerator.getInstance("DES");
        SecretKey sk_1 = kgen.generateKey(); 
        SecretKey sk_2 = kgen.generateKey();
        byte[] raw_1 = sk_1.getEncoded();
        byte[] raw_2 = sk_2.getEncoded();

        spec_1 = new SecretKeySpec(raw_1, "DES"); //key 1
        spec_2 = new SecretKeySpec(raw_2, "DES"); //key 2

        cipher = Cipher.getInstance("DES"); //standard mode is ECB which is block-by-block w/PKCS5Padding
        cipher2 = Cipher.getInstance("DES");


    protected byte[] get3DESEncryption(byte[] plaintext) throws Exception{
        byte[] output = new byte[plaintext.length];
        System.out.println("output len init: " + output.length);
        cipher.init(Cipher.ENCRYPT_MODE, spec_1);
        cipher2.init(Cipher.DECRYPT_MODE, spec_2);

        //first encryption round, key 1 used
        output = cipher.doFinal(plaintext);
        //second "encryption" round, key 2 used but decrypt run
        output = cipher2.doFinal(output);
        //third encryption round, key 1 used
        output = cipher.doFinal(output);

        //return ciphertext
        return output;
    } 

person j_l    schedule 09.10.2012    source источник
comment
Хороший вопрос; вы можете добавить spec_1 и spec_2, я думаю, что работа doFinal может зависеть от спецификации.   -  person Cory Kendall    schedule 09.10.2012
comment
Не могли бы вы добавить, пожалуйста, как вы создаете и шифр, и шифр2?   -  person Serge    schedule 09.10.2012


Ответы (1)


Проблема в том, что вы не должны использовать какие-либо отступы на втором (дешифрование) и третьем (шифрование) шагах. Когда вы на самом деле применяете EDE, вы должны заполнить только обычный текст.

Преобразование имеет вид:

«алгоритм/режим/заполнение» или «алгоритм» (в последнем случае используются значения по умолчанию для режима и схемы заполнения, определяемые провайдером).

Таким образом, вы должны явно указать ему не использовать заполнение для cipher2 и cipher3 (вы еще не создали последний).

Таким образом, у вас должно быть три объекта шифрования:

  • cipher1 DES/ECB/PKCS5Заполнение
  • cipher2 DES/ECB/NoPadding
  • cipher3 DES/ECB/NoPadding

[ДОПОЛНИТЕЛЬНАЯ ПОДСКАЗКА]

Для расшифровки вы должны инициализировать шифры по-другому, а также изменить порядок шифров.

person Serge    schedule 09.10.2012
comment
Вам не нужно беспокоиться об этом, потому что первое шифрование должно соответствующим образом дополнить вывод; так разве этот код не должен работать? - person Cory Kendall; 09.10.2012
comment
Да, из того, что я видел, начальная буква E будет правильным дополнением. Я только что использовал небольшие строки (т.е. тест), и он правильно заполняется от 4 байтов до 8. - person j_l; 09.10.2012
comment
ОП сталкивается с проблемой на втором этапе - это расшифровка. Если он неправильно инициализирован (с дополнением), то механизм шифрования пытается удалить дополнение после дешифрования, но это не удается, поскольку ключ для дешифрования отличается (как мы предполагаем) от ключа для шифрования. - person Serge; 09.10.2012
comment
Заполнение с помощью EDE используется только один раз, чтобы дополнить обычный текст длиной, кратной 8 символам (байтам). Затем происходит буквально шифрование-дешифрование-шифрование без промежуточного заполнения/распаковки - person Serge; 09.10.2012
comment
Кроме того, если cipher является экземпляром Cipher.getInstance(DES/PKCS5Padding), то третий шаг не следует выполнять с ним, так как промежуточный результат будет снова дополнен. - person Serge; 09.10.2012
comment
Серж, спасибо за инфу. У меня сложилось впечатление, что даже с указанным отступом он не будет повторно заполняться, если ввод будет кратен 8. - person j_l; 09.10.2012
comment
он всегда будет дополняться, если указан отступ, поскольку нет способа определить, были ли применены отступы или нет. - person Serge; 09.10.2012
comment
@Серж прав. Заполнение PKCS#5 всегда применяется при настройке. Причина этого в том, что последние байты обычного текста могут быть ошибочно приняты за заполнение: они могут иметь любое значение, в том числе совместимое с заполнением PKCS#5 (значение байта 01-08 в шестнадцатеричном формате). - person Maarten Bodewes; 09.10.2012