Issue
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());
}
Solution
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.
Answered By - Topaco
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.