1

I encrypt a text in Java and want to decrypt in Javascript and vice versa, my Java code looks like this

Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES"); c.init(Cipher.ENCRYPT_MODE, k); byte[] encryptedData = c.doFinal(this.value.getBytes()); byte[] iv = c.getIV(); sb.append(new String(Base64.getEncoder().encode(iv))); sb.append(';'); sb.append(new String(Base64.getEncoder().encode(encryptedData))); // send sb.toString() to the other end 

I tried node-forge and elliptic for decryption in Nodejs, in node-forge I have an error complaining about tag which I don't have, can someone provide a solution in Nodejs.

Javascript Code

function convertFromMxBase64(FormatEncryptedString) { const speratorIndex = FormatEncryptedString.indexOf(';'); const encryptedBase64 = mxFormatEncryptedString.substr(speratorIndex + 1); const ivBase64 = mxFormatEncryptedString.substr(0, speratorIndex); return { iv: forge.util.createBuffer(forge.util.decode64(ivBase64), 'utf8'), payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64), 'utf8') }; } function decrypt() { let { iv, payload } = convertFromMxBase64(mxCombi); const key = forge.util.createBuffer(theKey, 'utf8'); var cipher = forge.cipher.createDecipher("AES-GCM", key); // forge.rc2.createDecryptionCipher(key); cipher.start({ iv }); cipher.update(payload); cipher.finish(); var encrypted = cipher.output; // outputs encrypted hex console.log(encrypted.toHex()); } 
3
  • ...in node-forge I have an error complaining about tag which I don't have...: GCM has by definition a tag. The SunJCE provider in Java automatically appends it to the ciphertext (i.e. the last 16 bytes are the tag). Some libraries expect the tag detached, so you have to separate ciphertext and tag. Please post your NodeJS code for a more detailed analysis. Commented Feb 7, 2022 at 10:20
  • I can't get any tag from the Java Cipher class, I also add the javascript code Commented Feb 7, 2022 at 10:28
  • 1
    Full runnng examples for AES GCM string encryption can be found here (Java: github.com/java-crypto/cross_platform_crypto/blob/main/…) and here (NodeJS Forge: github.com/java-crypto/cross_platform_crypto/blob/main/…). Disclaimer: I'm the author). Commented Feb 7, 2022 at 14:32

1 Answer 1

1

The GCM mode uses by definition a tag which is needed for the authenticity/integrity check.
The tag issue on the NodeJS side is caused by not taking the authentication tag into account. On the Java side this is not necessary because the SunJCE provider does this automatically by appending the tag to the ciphertext: Therefore, the last 16 bytes of the result are the tag. On the NodeJS side, in contrast, ciphertext and tag are handled detached, so that both parts must be explicitly separated, e.g.:

var ciphertext = forge.util.createBuffer(payload.data.substring(0, payload.length() - 16)); var tag = forge.util.createBuffer(payload.data.substring(payload.length() - 16)); 

Tag and ciphertext must be passed to the cipher instance as follows:

cipher.start({ iv:iv, tag:tag }); // apply tag cipher.update(ciphertext); // apply ciphertext 

Another bug is that the UTF-8 encoding is used when creating iv and payload. This is wrong, the data must be passed as binary string, i.e. 'utf8' must either be replaced by 'binary' or removed completely.

iv: forge.util.createBuffer(forge.util.decode64(ivBase64)), payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64)) 

Also, in getBytes() of the Java code an encoding should be specified, e.g. getBytes(StandardCharsets.UTF_8). If this is not done, a platform-dependent default encoding is used, which means that different encodings can be applied depending on the environment.

With these changes, decryption works on the NodeJS side.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.