Search code examples
javascriptjavanode.jsencryptioncryptojs

using crypto library looks like cipher update is not working as expected?


i have crypto module to do string encryption when passed string is not 16 bytes i assume cipher.update() should do some padding and create 16 bytes string but that is not happening while debugging cipher.update returns empty string, is there other way to do padding using crypto.

index.js

function paymentIdencryption(text)

        const secret_key = "EiE0BVQle0xFjZvYOupKjFGHAcAwBaTjlZ7G7rryNos=";
        const secretKeyWordArray = CCrypto.enc.Utf8.parse(secret_key);

        const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(secret_key, 'base64'), iv);
        let encrypted = cipher.update(JSON.stringify(text), 'utf8', 'base64');
        encrypted += cipher.final('base64');
        const encryptedData = { iv: iv.toString('base64'), encrypted: encodeURIComponent(encrypted)};
       return encryptedData.encrypted;
}

console.log(paymentIdencryption("1384220_8089105");

Expected Result key Size :

GwJPNUfPXZZsuc0iqOFhn%2BYhMJKxXBUGl9g3iKqL8CE%3D

But it returns : jJtKhwjqS5N4ABIrZev8Ng%3D%3D

Java Code that does decryption

var imp = new JavaImporter(com.vordel.mime,org.json.simple.JSONObject,com.vordel.trace);
 
with(imp) {
function invoke(msg)         {            
 
var encodedKey = "${env.SPL.paymentMethodId.key}";
Trace.info ("env.SPL.paymentMethodId.key -- encodedKey  = " + encodedKey); 
var encodedPaymentInfo= msg.get("cvs.paymentMethodId");
 
var encryptedPaymentInfo = java.net.URLDecoder.decode(encodedPaymentInfo,"UTF-8");

var decodedKey = java.util.Base64.getDecoder().decode(encodedKey.getBytes("UTF-8"));
var decodedcipher = java.util.Base64.getDecoder().decode(encryptedPaymentInfo.getBytes("UTF-8"));

 
var cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding"); 
var secretKey = new javax.crypto.spec.SecretKeySpec(decodedKey, "AES"); 
var iv = new javax.crypto.spec.IvParameterSpec(decodedcipher,0,16);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE,secretKey,iv);
 
var decryptedPaymentInfo = cipher.doFinal(decodedcipher, 16, decodedcipher.length-16);
var paymentInfo = new java.lang.String(decryptedPaymentInfo,"UTF-8"); 
var patientId = paymentInfo.substring(paymentInfo.indexOf("_")+1, paymentInfo.length());
var paymentId = paymentInfo.substring(0, paymentInfo.indexOf("_"));
 
msg.put("cvs.spl.patientId",patientId);
msg.put("cvs.spl.paymentId",paymentId);
 
return true;         
 
}
};

Solution

  • The Java code performs a URL decoding of the encrypted data, followed by a Base64 decoding. The first 16 bytes of the result are used as IV, the rest as ciphertext.
    The key is Base64 decoded.
    With key and IV, the ciphertext is now decrypted with AES in CBC mode and PKCS#7 padding.
    The decrypted data is decoded with UTF-8.
    The patientid (the data after the _) and the paymentid (the data before the _) are extracted from the resulting string.

    From this, the logic for the encryption can be determined:

    • Base64 decoding of the key
    • generation of a random 16 bytes IV
    • encryption with aes-256-cbc (AES-256 because of the 32 bytes key) using key and IV
    • concatenation of IV and ciphertext
    • Base64 encoding of the ciphertext with subsequent URL encoding

    Possible NodeJS implementation:

    var crypto = require('crypto')
    function paymentIdencryption(text) {
        const secret_key = "EiE0BVQle0xFjZvYOupKjFGHAcAwBaTjlZ7G7rryNos=";
        const iv = crypto.randomBytes(16);
        const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(secret_key, 'base64'), iv);
        const encrypted = Buffer.concat([iv, cipher.update(text, 'utf8'), cipher.final()]);
        return encodeURIComponent(encrypted.toString('base64'))
    }
    console.log(paymentIdencryption("1384220_8089105"));
    

    Possible output (changes for each encryption because of the random IV):

    5I43wWYs84XQk9Pe0IMl4g%2B7s%2BgwcJrPsWo9gcX25y8%3D 
    

    Test with the Java code:

    public class Main {
        public static void main(String[] args) throws Exception {
            
            var encodedPaymentInfo = "5I43wWYs84XQk9Pe0IMl4g%2B7s%2BgwcJrPsWo9gcX25y8%3D"; 
            var encodedKey = "EiE0BVQle0xFjZvYOupKjFGHAcAwBaTjlZ7G7rryNos=";
            
            var encryptedPaymentInfo = java.net.URLDecoder.decode(encodedPaymentInfo,"UTF-8");
    
            var decodedKey = java.util.Base64.getDecoder().decode(encodedKey.getBytes("UTF-8"));
            var decodedcipher = java.util.Base64.getDecoder().decode(encryptedPaymentInfo.getBytes("UTF-8"));
             
            var cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding"); 
            var secretKey = new javax.crypto.spec.SecretKeySpec(decodedKey, "AES"); 
            var iv = new javax.crypto.spec.IvParameterSpec(decodedcipher,0,16);
            cipher.init(javax.crypto.Cipher.DECRYPT_MODE,secretKey,iv);
             
            var decryptedPaymentInfo = cipher.doFinal(decodedcipher, 16, decodedcipher.length-16);
            var paymentInfo = new java.lang.String(decryptedPaymentInfo,"UTF-8"); 
            var patientId = paymentInfo.substring(paymentInfo.indexOf("_")+1, paymentInfo.length());
            var paymentId = paymentInfo.substring(0, paymentInfo.indexOf("_"));
             
            System.out.println("cvs.spl.patientId: " + patientId);
            System.out.println("cvs.spl.paymentId: " + paymentId);
        }
    }
    

    Output:

    cvs.spl.patientId: 8089105
    cvs.spl.paymentId: 1384220
    

    which is equal to the data of the original plaintext.