Шифрование AES на java и дешифрование в javascript с использованием CryptoJS

#java #encryption #cryptography #aes #cryptojs

#java #шифрование #криптография #aes #cryptojs

Вопрос:

Ниже приведен код для шифрования некоторого содержимого файла в Java с использованием режима AES / CTR / NOPADDING. Я использую криптопакет javax. Также я использую тот же секретный ключ для генерации ключа и iv.

 Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

        byte[] secretKey = Base64.decodeBase64("uQsaW WMUrjcsq1HMf 2JQ==");

        SecretKeySpec key = new SecretKeySpec(secretKey, "AES");
        IvParameterSpec iv = new IvParameterSpec(secretKey);

        cipher.init(mode, key , iv);

        FileInputStream fileInputStream = new FileInputStream(sourceFilePath);
        FileOutputStream fileOutputStream = new FileOutputStream(destFilePath);

        int read = 0;
        while ((fileInputStream.available()) > 0) {
            byte[] block = new byte[4096];
            read = fileInputStream.read(block);
            byte[] writeBuffer = cipher.update(block);
            fileOutputStream.write(writeBuffer, 0, read);
        }

        byte[] writeBuffer = cipher.doFinal();
        fileOutputStream.write(writeBuffer, 0, writeBuffer.length);

        fileInputStream.close();
        fileOutputStream.close();
  

Я не могу расшифровать зашифрованный контент в javascript с помощью cryptojs.
Вот что я попробовал.

 var key = CryptoJS.enc.Hex.parse(atob('uQsaW WMUrjcsq1HMf 2JQ=='));

var decrypted = CryptoJS.AES.decrypt(encryptedContent, key, {
    mode: CryptoJS.mode.CTR,
    iv: key,
    padding: CryptoJS.pad.NoPadding
});

var decryptedText = CryptoJS.enc.Utf8.stringify(decrypted);
  

Может кто-нибудь сказать мне, что я делаю не так? Или скажите мне, как это сделать.

Я могу шифровать и расшифровывать на java и javascript независимо.

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

1. Использовать ключ в качестве IV — это очень плохая идея, особенно для режима CTR. Нужно ли предоставлять ключ для nodejs в шестнадцатеричном формате?

2. да, CryptoJS принимает key и iv как шестнадцатеричные.

3. Да, я читал то же самое, что использование ключа в качестве iv плохо, но в текущей ситуации что еще происходит не так. @gusto2 Спасибо.

4. что вы подразумеваете под «не удается расшифровать»? Есть ли у вас исключение (post the stacktrace) или искаженный вывод?

5. CryptoJS возвращает wordArray в качестве выходных данных. Он выдает пустой wordArray. Никаких исключений или ошибок. Также я исправил ключ, который передается методу decrypt. Ранее это передавалось как массив слов [0,256].

Ответ №1:

  • В CryptoJS документации объясняется, какие типы данных и параметры ожидает CryptoJS.decrypt() метод и какие кодировщики доступны:

    • Ключ должен быть передан CryptoJS.decrypt() -методу как WordArray . Поскольку ключевые данные закодированы в Base64, они могут быть преобразованы в WordArray с CryptoJS.enc.Base64.parse() помощью-method.
    • Зашифрованный текст может быть передан CryptoJS.decrypt() -методу как WordArray внутри CipherParams -объекта. Java-код хранит зашифрованные данные в файле. Предполагая, что строка encryptedContent содержит эти данные в виде шестнадцатеричной строки (к сожалению, это не вытекает из опубликованного кода, так что здесь должно быть сделано предположение), они могут быть преобразованы в WordArray с помощью CryptoJS.enc.Hex.parse() -метода и обернуты в CipherParams -объект.
    • CryptoJS.decrypt() -Метод возвращает WordArray , который может быть преобразован с помощью CryptoJS.enc.Utf8.stringify() -метода в строку.
  • Если во входном файле содержится следующий простой текст:

     This is the plain text which needs to be encrypted!
      

    Java-код сохраняет следующую последовательность байтов (= зашифрованные данные) в выходном файле:

     52F415AB673427C42278E8D6F34C16134D7E3FE7986500980ED4063F3CF51162592CE0F5412CCA0BC2DBAE3F2AEC2D585EE8D7
      

    JavaScript-код для дешифрования является:

     var key = CryptoJS.enc.Base64.parse('uQsaW WMUrjcsq1HMf 2JQ==');
    
    var encryptedContent = '52F415AB673427C42278E8D6F34C16134D7E3FE7986500980ED4063F3CF51162592CE0F5412CCA0BC2DBAE3F2AEC2D585EE8D7';
    var cipherParams = CryptoJS.lib.CipherParams.create({
        ciphertext: CryptoJS.enc.Hex.parse(encryptedContent)         
    });
    
    var decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
        mode: CryptoJS.mode.CTR,
        iv: key,
        padding: CryptoJS.pad.NoPadding
    });
    
    var decryptedText = CryptoJS.enc.Utf8.stringify(decrypted);
    console.log(decryptedText); 
      

который отображает исходный обычный текст в консоли. Для запуска приведенного выше кода необходима как минимум версия CryptoJS 3.1.4 (см. Версии, cdnjs).

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

1. Спасибо @Topaco. Я думаю, что есть некоторая проблема с моей кодировкой в java, я использую приведенный выше код, но я получаю несколько случайных символов (нечитаемых) в качестве зашифрованных данных. Я проверил свой импорт, я использую javax.crypto.

2. Вам пришлось бы более подробно описать, как зашифрованные данные считываются из сохраненного файла в JavaScript-код (или, точнее, в переменную encryptedContent ). Это не видно из вашего кода. Вероятно, проблема здесь. Лучший способ — опубликовать недостающий код. Или вы пытаетесь определить зашифрованные данные из файла вручную ? В этом случае вы должны использовать не текстовый редактор, а шестнадцатеричный , поскольку требуется шестнадцатеричное представление зашифрованных данных.

3. На самом деле я говорил о коде Java. Когда я записываю зашифрованный контент в файл на java, он записывается с некоторыми случайными символами (многие символы, не являющиеся клавиатурными). Код Java в том виде, в каком он скопирован, без импорта и попытки перехватить блок. В JavaScript я перехватываю запрос на выборку файла и считываю содержимое в виде текста.

4. Зашифрованные данные состоят из байтов со значениями между 0x00 и 0xFF . Если вы открываете файл в текстовом редакторе, то в зависимости от кодировки отображаются буквенно-цифровые символы, специальные символы, управляющие символы и т.д. (Что вполне нормально). Я полагаю, вы имеете в виду это. Чтобы увидеть actual (шестнадцатеричные) значения, вы должны открыть файл в шестнадцатеричном редакторе. Наконец, задача состоит в том, чтобы предоставить эти шестнадцатеричные значения в JavaScript-коде, чтобы можно было выполнить дешифрование.

5. Для дальнейшего анализа вы могли бы продолжить шаг за шагом: Создайте файл с зашифрованными данными с открытым текстом из моего ответа: Это обычный текст, который необходимо зашифровать! . Содержит ли сгенерированный файл шестнадцатеричные значения из моего ответа: 52F415AB673427C42278E8D6F34C16134D7E3FE7986500980ED4063F3CF51162592CE0F5412CCA0BC2DBAE3F2AEC2D585EE8D7 ? Следующий шаг — проверить, содержатся ли эти значения также в JavaScript-коде в encryptedContent . Я подозреваю, что проблема возникает на последнем шаге.

Ответ №2:

Ваш цикл шифрования неверен. Я не уверен, является ли это причиной ваших проблем, но я бы начал с этого

 read = fileInputStream.read(block);
byte[] writeBuffer = cipher.update(block);
  

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

 byte[] writeBuffer = cipher.update(block, 0, read);
  

Что касается использования ключа в качестве IV, я должен подчеркнуть, что в режиме CTR безопасность будет полностью нарушена.

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

1. Спасибо за предложение. Это не сработало. Обратите внимание, что я могу расшифровать в java, используя те же шаги, что и в написанном в методе, и просто изменив режим экземпляра cipher.