Получение ошибки (Ошибка: неподдерживаемое состояние или невозможно подтвердить подлинность данных) в расшифровке nodejs

Я зашифровал сообщение с использованием алгоритма AES/GCM/NoPadding (AES-256) в Java и пытался расшифровать его в NodeJs. Получение исключения "Ошибка: неподдерживаемое состояние или невозможно подтвердить подлинность данных" во время расшифровки. Ниже приведен полный код java и nodejs и сообщение об ошибке: Pl, помогите мне найти неправильный код в java или nodejs.

Ниже приведен код, начинающийся с кода шифрования Java:

 public static String encryptAES(String privateString, String skey) throws Exception{   
    byte[] iv = new byte[GCM_IV_BYTES_LENGTH]; //12 iv length
    byte[] tag = new byte[GCM_TAG_BYTES_LENGTH]; //16 tag length
    (new SecureRandom()).nextBytes(iv);
    (new SecureRandom()).nextBytes(tag);

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); //algorithm type
    GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * Byte.SIZE, iv);
    cipher.init(Cipher.ENCRYPT_MODE, getKey(skey), ivSpec);

    byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));

    byte[] ivTag = new byte[GCM_IV_BYTES_LENGTH + GCM_TAG_BYTES_LENGTH]; // merging iv and tag
    System.arraycopy(iv, 0, ivTag, 0, iv.length);
    System.arraycopy(tag, 0, ivTag, iv.length, tag.length);

    byte[] encrypted = new byte[ivTag.length + ciphertext.length]; //merging ivtag and cipher
    System.arraycopy(ivTag, 0, encrypted, 0, ivTag.length);
    System.arraycopy(ciphertext, 0, encrypted, ivTag.length, ciphertext.length);

    String encoded = Base64.getEncoder().encodeToString(encrypted); //b64 encoded value
    System.out.println("encrypted str:>" + encoded.length() + " | " + encoded);
    return encoded;
}

// Код расшифровки NodeJS:

function decryptTokenResponse(encryptedStr){
    let data = encryptedStr
    const bData = Buffer.from(data, 'base64');

    const iv = bData.slice(0, 12);
    const tag = bData.slice(12, 28);
    const text = bData.slice(28);

    var decipher = crypto.createDecipheriv(algorithm,masterkey, iv)
    decipher.setAuthTag(tag)
    var plainText = decipher.update(text,'base64','utf-8');
    plainText += decipher.final('utf-8'); **//getting exception here**
    console.log('Decrypted data = ' + plainText)
}           


**//Error :**

                internal/crypto/cipher.js:145
                  const ret = this._handle.final();
                                           ^

                Error: Unsupported state or unable to authenticate data
                    at Decipheriv.final (internal/crypto/cipher.js:145:28)
                    at decryptTokenResponse (/home/jdoodle.js:40:27)
                    at Object.<anonymous> (/home/jdoodle.js:18:1)
                    at Module._compile (internal/modules/cjs/loader.js:678:30)
                    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
                    at Module.load (internal/modules/cjs/loader.js:589:32)
                    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
                    at Function.Module._load (internal/modules/cjs/loader.js:520:3)
                    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
                    at startup (internal/bootstrap/node.js:228:19)
                Command exited with non-zero status 1

3 ответа

Authtag для GCM или CCM генерируется операцией шифрования - вы не генерируете его случайным образом самостоятельно (как вы делаете или, по крайней мере, можете для IV/nonce). Однако он в некотором роде скрыт, потому что Java crypto встраивает аутентифицированное шифрование в свой ранее существующий API, добавляя тег к зашифрованному тексту, возвращенному операцией шифрования, или вводя в операцию дешифрования. OTOH nodejs/OpenSSL рассматривает их как отдельные значения. (И Java, и nodejs / OpenSSL рассматривают AAD как отдельный, но вы не используете AAD.)

Поскольку вы уже собираете вещи вместе (и base64ing) для передачи, вы должны:

  • в Java объедините IV плюс возврат из cipher.doFinal (который является тегом ctx +), формирующий тег IV + ctx +

  • Base64 и отправить и после получения de-base64, как вы уже делаете

  • в nodejs разделите их на IV, CTX, тег, который легко, потому что Buffer можно нарезать с обоих концов: bData.slice(0,12) bData.slice(12,-16) bData.slice(-16)

Также ваш text уже de-base64-ed, но так как это Buffer inputEncoding для decipher.update игнорируется

Вы должны предоставить AuthenticationTag в createDeCipherIv() когда используешь AES в GCM, CCM а также OCBрежимы.

Зачем вам внедрять GCM без этого? Вы можете также использовать CTR Режим AES, если вы не хотите дополнительных защит.

Я каким-то образом понял, как это будет работать для меня, я получал ту же ошибку, а затем наблюдал ее снова и снова для одного и того же шифрования. Я обнаружил, что всякий раз, когда зашифрованный вывод содержит символ «/» или «+», я получаю ту же ошибку . Затем я использовал цикл while, чтобы продолжать шифрование снова и снова, пока вывод не будет содержать символы, и дать вывод, который не имеет ни одного из этих двух символов. Это сработало для меня таким образом. Надеюсь, что это сработает и для вас.

Другие вопросы по тегам