【问题标题】:Getting error(Error: Unsupported state or unable to authenticate data) in nodejs decryption在 nodejs 解密中出现错误(错误:不支持的状态或无法验证数据)
【发布时间】:2018-08-23 06:40:38
【问题描述】:

我在 java 中使用 AES/GCM/NoPadding 算法 (AES-256) 加密了一条消息,并尝试在 NodeJs 中对其进行解密。解密时出现异常“错误:不支持的状态或无法验证数据”。下面是java和nodejs的完整代码&错误信息: 请帮助我在 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

【问题讨论】:

    标签: java node.js node-crypto


    【解决方案1】:

    GCM 或 CCM 的 authtag 由加密操作生成——您不会自己随机生成它(就像您这样做,或者至少可以,对于IV/nonce)。但是它有点隐藏,因为 Java 加密通过将标记附加到加密操作返回的密文或解密操作的输入,将经过身份验证的加密融入其预先存在的 API。 OTOH nodejs/OpenSSL 将它们视为单独的值。 (Java 和 nodejs/OpenSSL 都将 AAD 视为独立的,但您没有使用 AAD。)

    由于您已经将东西打包在一起(和 base64ing)以进行传输,您应该:

    • 在 Java 中,连接 IV 加上 cipher.doFinal 的返回值(即 ctx + tag),形成 IV + ctx + tag

    • base64 和发送和接收 de-base64 之后,就像你已经做的那样

    • 在 nodejs 中,将这些拆分为 IV,ctx,tag 这很容易,因为Buffer 可以从两端切片:bData.slice(0,12) bData.slice(12,-16) bData.slice(-16)

    此外,您的 text 已经是 de-base64-ed,但由于它是 Buffer,因此 decipher.update 的 inputEncoding 将被忽略。

    【讨论】:

    • 感谢您的回答!它对我有用。我在decipher.final(utf8) 中提供编码,但在crypto.createDecipherivdecipher.update 中分别使用ascii 字符串而不是iv 和 encryptedText 的缓冲区。在将它们更改为缓冲区然后使用slice 之后,我得到了它的工作。谢谢!
    【解决方案2】:

    GCMCCMOCBmodes 中使用AES 时,您必须提供AuthenticationTagcreateDeCipherIv()

    没有它,你为什么要实现GCM?如果您不想要额外的保护,也可以使用 AES 的CTR 模式。

    【讨论】:

    • 不是在createCipheriv 上,而是在decipher 对象上调用setAuthTag——就像OP 一样。此外,OFB 不是 AE 模式; ITYM OCB。但是 Java 不做 OCB,至少现在还没有。
    • 谢谢。我的意思是OFBdecryptCipherIv()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 2021-06-17
    • 2020-09-28
    • 1970-01-01
    相关资源
    最近更新 更多