AES/CBC/PKCS5Padding in NodeJs

I am trying to convert my java code to NodeJs code.
Facing some issues on the encryptions.
Here is my java code: compiled code

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.Base64;

public class AESCBCPKCS5Encryption {
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";

    public static String encrypt(String message, String key) throws GeneralSecurityException, UnsupportedEncodingException {
        if (message == null || key == null) {
            throw new IllegalArgumentException("text to be encrypted and key should not be null");
        }
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        byte[] messageArr = message.getBytes();
        SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        byte[] ivParams = new byte[16];
        byte[] encoded = new byte[messageArr.length + 16];
        System.arraycopy(ivParams, 0, encoded, 0, 16);
        System.arraycopy(messageArr, 0, encoded, 16, messageArr.length);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivParams));
        byte[] encryptedBytes = cipher.doFinal(encoded);
        encryptedBytes = Base64.getEncoder().encode(encryptedBytes);
        return new String(encryptedBytes);
    }

    public static String decrypt(String encryptedStr, String key) throws GeneralSecurityException, UnsupportedEncodingException {
        if (encryptedStr == null || key == null) {
            throw new IllegalArgumentException("text to be decrypted and key should not be null");
        }
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        SecretKeySpec keySpec = new
                SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        byte[] encoded = encryptedStr.getBytes();
        encoded = Base64.getDecoder().decode(encoded);
        byte[] decodedEncrypted = new byte[encoded.length - 16];
        System.arraycopy(encoded, 16, decodedEncrypted, 0, encoded.length - 16);
        byte[] ivParams = new byte[16];
        System.arraycopy(encoded, 0, ivParams, 0, ivParams.length);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivParams));
        byte[] decryptedBytes = cipher.doFinal(decodedEncrypted);
        return new String(decryptedBytes);
    }

    public static void main(String[] args) throws GeneralSecurityException, UnsupportedEncodingException {
        String str = "<Request xmlns=\"http://www.kotak.com/schemas/CorpCCPaymentsOTP/CorpCCPaymentsOTP.xsd\" ><username>ENKASH</username><password>Corp@123</password><SrcAppCd>ENKA SH</SrcAppCd><RefNo>Ref1111111111</RefNo><CardNo>4280933990002698</CardNo ><OTP>12345</OTP></Request>";
        String key = "e3a74e3c7599f3ab4601d587bd2cc768";
        String enc = encrypt(str, key);
        System.out.println(enc);
        String dec = decrypt(enc, key);
        System.out.println(dec);
    }
}

Here is my javascript code:

var crypto = require('crypto');

function getAlgorithm(keyBase64) {

    var key = Buffer.from(keyBase64, 'base64');
    switch (key.length) {
        case 16:
            return 'aes-128-cbc';
        case 32:
            return 'aes-256-cbc';

    }

    throw new Error('Invalid key length: ' + key.length);
}


function encrypt(plainText, keyBase64, ivBase64) {

    const key = Buffer.from(keyBase64, 'base64');
    const iv  = Buffer.from(ivBase64, 'base64');

    const cipher  = crypto.createCipheriv(getAlgorithm(keyBase64), key, iv);
    let encrypted = cipher.update(plainText, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

function decrypt(messagebase64, keyBase64, ivBase64) {

    const key = Buffer.from(keyBase64, 'base64');
    const iv  = Buffer.from(ivBase64, 'base64');

    const decipher = crypto.createDecipheriv(getAlgorithm(keyBase64), key, iv);
    let decrypted  = decipher.update(messagebase64, 'base64');
    decrypted += decipher.final();
    return decrypted;
}


var keyBase64 = "DWIzFkO22qfVMgx2fIsxOXnwz10pRuZfFJBvf4RS3eY=";
var ivBase64  = 'e3a74e3c7599f3ab4601d587bd2cc768';
var plainText = '<Request xmlns="http://www.kotak.com/schemas/CorpCCPaymentsOTP/CorpCCPaymentsOTP.xsd"><username>ENKASH</username><password>Corp@123</password><SrcAppCd>ENKA SH</SrcAppCd><RefNo>Ref1111111111</RefNo><CardNo>4280933990002698</CardNo ><OTP>12345</OTP></Request>';

var cipherText          = encrypt(plainText, keyBase64, ivBase64);
var decryptedCipherText = decrypt(cipherText, keyBase64, ivBase64);

console.log('Algorithm: ' + getAlgorithm(keyBase64));
console.log('Plaintext: ' + plainText);
console.log('Ciphertext: ' + cipherText);
console.log('Decoded Ciphertext: ' + decryptedCipherText);

Encryptions throwing errors,
What I am doing wrong here?

1 answer

  • answered 2020-01-17 14:04 Gaurav Dhiman

    Initialization vector length of AES in CBC mode is 16 Bytes, code in JAVA takes first 16 bytes of IV however for node.js code it uses all 24 bytes of IV, hence an error. try this code

    var crypto = require('crypto');
    
    function getAlgorithm(keyBase64) {
    
        var key = Buffer.from(keyBase64, 'base64');
        switch (key.length) {
            case 16:
                return 'aes-128-cbc';
            case 32:
                return 'aes-256-cbc';
    
        }
    
        throw new Error('Invalid key length: ' + key.length);
    }
    
    
    function encrypt(plainText, keyBase64, ivBase64) {
    
        const key = Buffer.from(keyBase64, 'base64');
        const iv  = Buffer.from(ivBase64, 'base64');
    
        const cipher  = crypto.createCipheriv(getAlgorithm(keyBase64), key, iv.slice(0, 16));
        let encrypted = cipher.update(plainText, 'utf8', 'base64');
        encrypted += cipher.final('base64');
        return encrypted;
    }
    
    function decrypt(messagebase64, keyBase64, ivBase64) {
    
        const key = Buffer.from(keyBase64, 'base64');
        const iv  = Buffer.from(ivBase64, 'base64');
    
        const decipher = crypto.createDecipheriv(getAlgorithm(keyBase64), key, iv.slice(0, 16));
        let decrypted  = decipher.update(messagebase64, 'base64');
        decrypted += decipher.final();
        return decrypted;
    }
    
    
    var keyBase64 = "DWIzFkO22qfVMgx2fIsxOXnwz10pRuZfFJBvf4RS3eY=";
    var ivBase64  = 'e3a74e3c7599f3ab4601d587bd2cc768';
    var plainText = '<Request xmlns="http://www.kotak.com/schemas/CorpCCPaymentsOTP/CorpCCPaymentsOTP.xsd"><username>ENKASH</username><password>Corp@123</password><SrcAppCd>ENKA SH</SrcAppCd><RefNo>Ref1111111111</RefNo><CardNo>4280933990002698</CardNo ><OTP>12345</OTP></Request>';
    
    var cipherText          = encrypt(plainText, keyBase64, ivBase64);
    var decryptedCipherText = decrypt(cipherText, keyBase64, ivBase64);
    
    console.log('Algorithm: ' + getAlgorithm(keyBase64));
    console.log('Plaintext: ' + plainText);
    console.log('Ciphertext: ' + cipherText);
    console.log('Decoded Ciphertext: ' + decryptedCipherText);