我在java中使用AES / GCM / NoPadding算法(AES-256)加密了一条消息并尝试在NodeJ中解密它。解密时获取异常“错误:不支持的状态或无法验证数据”。下面是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
GCM或CCM的authtag是由加密操作生成的 - 您不会自己随机生成(就像您一样,或者至少可以为IV / nonce生成)。但是它有点隐藏,因为Java加密通过将标记附加到加密操作返回的密文或输入到解密操作来将经过身份验证的加密符合到其预先存在的API中。 OTOH nodejs / OpenSSL将它们视为单独的值。 (Java和nodejs / OpenSSL都将AAD视为单独的,但您没有使用AAD。)
由于您已经将所有东西(和base64ing)打包在一起进行传输,因此您应该:
Buffer
可以从两端切片:bData.slice(0,12) bData.slice(12,-16) bData.slice(-16)
另外你的text
已经去基础64-ed,但是因为它是Buffer
,所以忽略了对decipher.update
的inputEncoding。
当你在AuthenticationTag
,createDeCipherIv()
和AES
modes中使用GCM
时,你必须向CCM
提供OCB
。
如果没有它,你为什么要实施GCM
?如果您不想要额外的保护,您也可以使用AES的CTR
模式。