Issue
NodeJs:
I am trying decrypt text using AES CBC PKCS7 in NodeJs and PKCS5 in java. I am getting error: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
UPDATED
encrypt() {
var key = 'ThirtyTwoBytes3$ThirtyTwoBytes3$';
var iv = CryptoJS.enc.Utf8.parse(CryptoJS.lib.WordArray.random(128 / 8));
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), key, {mode:
CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv});
return iv.concat(encVal.ciphertext).toString(CryptoJS.enc.Base64);
}
Java:
byte[] keyB = "ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptedText.getBytes(), 0, 16);
SecretKeySpec key = new SecretKeySpec(keyB, "AES");
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
byte[] decryptedData = Base64.getDecoder().decode(encryptedText);
decryptedText = new String(Hex.decodeHex(new String(aesCBC.doFinal(decryptedData), StandardCharsets.UTF_8).toCharArray()));
Fixed IV is working fine
NodeJs
var encKey = CryptoJS.enc.Utf8.parse("ThirtyTwoBytes3$ThirtyTwoBytes3$");
var encKeyIv = CryptoJS.enc.Utf8.parse("$1SixteenBytes6$");
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), encKey, {mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: encKeyIv});
encVal.ciphertext.toString();
Java:
SecretKey key = new SecretKeySpec("ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec("$1SixteenBytes6$".getBytes());
byte[] decodeBase64 = Base64.decode(encVal);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
decString = new String(Hex.decodeHex(new String(cipher.doFinal(decodeBase64), "UTF-8").toCharArray()));
Solution
There are a few issues in the CryptoJS part, apply the following fixes:
const iv = CryptoJS.lib.WordArray.random(128 / 8); // no UTF8 encoding, this corrupts the data
...
encrypted = iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64); // typo in ciphertext; use base64 encoding because of the built-in support in Java
return encrypted; // return the data
In the Java code, IV and ciphertext must be separated, e.g.:
import java.nio.ByteBuffer;
import java.util.Base64;
...
String ivCiphertextB64 = "zuXYG1IbUNsiQYSTBUCv+Rx37EpJTw9SWfhRkL3yw2GncOvBDNU+w6UdB+ovfL2LyiCMYF1ptiXvuWynngc76Q=="; // data from CryptoJS code
byte[] ivCiphertext = Base64.getDecoder().decode(ivCiphertextB64);
ByteBuffer bufIvCiphertext = ByteBuffer.wrap(ivCiphertext);
byte[] iv = new byte[16];
bufIvCiphertext.get(iv);
byte[] ciphertext = new byte[bufIvCiphertext.remaining()];
bufIvCiphertext.get(ciphertext);
...
iv
is passed in new IvParameterSpec(iv)
, ciphertext
in aesCBC.doFinal(ciphertext)
. This decrypts the above ciphertext in The quick brown fox jumps over the lazy dog.
Edit:
Regarding your comment: In the modified CryptoJS code of your question the random IV is still Utf8 encoded. This Utf8 encoding is wrong because it corrupts the random data (s. e.g. here) and needs to be changed as already described above. Below you will find the complete, working CryptoJS code. A ciphertext generated with this code can be decrypted with the modified Java code.
function encrypt() {
const _key = CryptoJS.enc.Utf8.parse('ThirtyTwoBytes3$ThirtyTwoBytes3$');
const iv = CryptoJS.lib.WordArray.random(128 / 8);
let encrypted = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse('The quick brown fox jumps over the lazy dog'),
_key,
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
}
);
encrypted = iv
.concat(encrypted.ciphertext)
.toString(CryptoJS.enc.Base64);
return encrypted;
}
document.getElementById("ct").innerHTML = encrypt();
<p style="font-family:'Courier New', monospace;" id="ct"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
Answered By - Topaco
Answer Checked By - David Marino (JavaFixing Volunteer)