Reputation: 41
I'm trying to decrypt encrypted data in nodejs and the data is encrypted in java by other authentication service provider.
The decrypting code works fine with data encrypted in nodejs as same way as their guideline. However, it makes error with data from the service.
First, here is their encrypting code
String res_data = ""
String key = "" //16bytes encoded string which is made when I call their auth module
String iv = "" //16bytes encoded string which is made when I call their auth module
SecretKey secureKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes()));
byte[] encrypted = c.doFinal(enc_data.trim().getBytes());
Encoder encoder = Base64.getEncoder();
byte[] encodedBytes = encoder.encode(encrypted);
String resDataEnc = new String(encodedBytes)
coresponding nodejs encrypting code which works fine and has no error
//variables same as above
const res_data = ""
const key = ""
const iv = ""
const cipher = crypto.createCipheriv("aes-128-cbc", key, iv);
const encrypted = cipher.update(enc_data, "utf8", "base64")
const resDataEnc = encrypted + cipher.final("base64")
Here is my decrypting code that make Error
const enc_data = "" //encoded data from service
const key = "" //same as above
const iv = "" //same as above
const decipher = crypto.createDecipheriv("aes-128-cbc", key, iv);
const decrypted = decipher.update(enc_data, "base64", "utf8")
//decrypted.toString() returns successfully decoded data
//here's what I tried
const resData = decrypted + decipher.final("utf8")
//it returns Error "wrong final block length" at decipher.final
//another try
const resData = Buffer.concat([decrypted + decipher.final("utf8")])
const euckrDecode = iconv.decode(response, "euc-kr")
//it returns same error
Here is their decrypting guideline code
//same data as written above
String enc_data = ""
String key = ""
String iv = ""
SecretKey secureKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes()));
byte[] cipherEnc = Base64Util.decode(encData.trim().getBytes());
String resData = new String(c.doFinal(cipherEnc), "euc-kr");
As I look for, java and nodejs has different type of padding when encrypting, is it the problem? It is decoded fine in java but not in nodejs. Is there a problem at converting from java to nodejs or is there other fact that i miss?
please share your knowledge. thank you
Upvotes: 1
Views: 305
Reputation: 12087
There are multiple issues with this code:
String key = "" //16bytes encoded string which is made when I call their auth module
String iv = "" //16bytes encoded string which is made when I call their auth module
For the CBC mode the IV needs to be random (unpredictable), no fixed, otherwise some attack vectors are possible.
Key and IV in the direct String type assumes using the printable characters which limits security (strength) of the key.
const encrypted = cipher.update(enc_data, "utf8", "base64")
const resDataEnc = encrypted + cipher.final("base64")
....
const resData = decrypted + decipher.final("utf8")
//it returns Error "wrong final block length" at decipher.final
Concatenating two base64-encoded strings doesn't necessary produce another valid base64 encoded string. It may happen accidently, when having the input length as multiple of 3. If the base64 padding is not used, you don't spot it upfront. That is valid for utf-8 too, mainly when handling multi-byte charsets, such as from Asia.
When encrypting/decrypting, you should rather the work with byte arrays (Buffer) and then encode or decode the result, e.g.
const resDataEnc = Buffer.concat(
[ cipher.update( Buffer.from(enc_data, 'base64')), cipher.final() ]
).toString('utf-8');
const resData = decrypted + decipher.final("utf8")
//it returns Error "wrong final block length" at decipher.final
Trying to decrypt the invalid input (concatenated two base64 encoded strings), the decoded input may not have required length (multiple of 16).
Basically - check that the decoded input must have multiple of the block size (16 bytes)
Upvotes: 1