Search code examples
javascriptpython-3.xencryptioncryptojspostman-pre-request-script

decrypting CyproJS AES encryption in Cryptodome python


I am trying to decrypt message (in python) that has been encoded using CryptoJS in JavaScript. I have created an API in python, to post data I am using postman pre-request script.

The Error I am getting:

ValueError: Data must be padded to 16 byte boundary in CBC mode

JavaScript code for encryption

var data = {"feature_0": 0,
            "feature_1": 0, 
            "feature_2": 0, 
            "feature_3": 0, 
            "feature_4": 0, 
            "feature_5": 0
           };
let password = "lazydog";
let salt = "salt";
let iterations = 128;
data = JSON.stringify(data);
let len = 16 - ((data.length) % 16);
data += len.toString().repeat(len);  --> removed (as suggested)
let bytes = CryptoJS.PBKDF2(password, salt, { keySize: 48, iterations: iterations });
let iv = CryptoJS.enc.Hex.parse(bytes.toString().slice(0, 32));
let key = CryptoJS.enc.Hex.parse(bytes.toString().slice(32, 96));

let encrypted = CryptoJS.AES.encrypt(data, key, {iv: iv}); //, mode: CryptoJS.mode.CBC
//encrypted = btoa(encrypted); --> removed (as suggested)
encrypted = encrypted.toString() -->added (as suggested)
postman.setGlobalVariable("data", encrypted);

python code for decryption:

def decode(encrypted):
    data = b64decode(encrypted)  
    byte = PBKDF2("lazydog".encode("utf-8"), "salt".encode("utf-8"), 48, 128)
    iv = byte[0:16]
    key = byte[16:48]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    text = cipher.decrypt(data) ## error is at this line
    text = text[:-text[-1]].decode("utf-8")

    return text

As the error said padding problem I added padding in JS code. Still I am not getting good results. What's wrong I am doing here?


Solution

  • The encrypted string has posted to API which has written in python. I don't know why but when encrypted passed to python '+' chars are being replaced with ' '(space). By replacing the spaces with '+' char I resolved the problem.

    code

    var data = {"feature_0": 0,
            "feature_1": 0, 
            "feature_2": 0, 
            "feature_3": 0, 
            "feature_4": 0, 
            "feature_5": 0
           };
    let password = "lazydog";
    let salt = "salt";
    let iterations = 128;
    data = JSON.stringify(data);
    let bytes = CryptoJS.PBKDF2(password, salt, { keySize: 48, iterations: 
      iterations });
    let iv = CryptoJS.enc.Hex.parse(bytes.toString().slice(0, 32));
    let key = CryptoJS.enc.Hex.parse(bytes.toString().slice(32, 96));
    
    let encrypted = CryptoJS.AES.encrypt(data, key, {iv: iv});
    encrypted = encrypted.toString()
    postman.setGlobalVariable("data", encrypted);
    

    python code

    def decode(encrypted):
        encrypted = encrypted.replace(' ', '+') --> this line is added
        data = b64decode(encrypted)  
        byte = PBKDF2("lazydog".encode("utf-8"), "salt".encode("utf-8"), 48, 128)
        iv = byte[0:16]
        key = byte[16:48]
        cipher = AES.new(key, AES.MODE_CBC, iv)
        text = cipher.decrypt(data) ## error is at this line
        text = text[:-text[-1]].decode("utf-8")
    
        return text
    

    As CryptoJs pads data implicitly custom padding has been removed. And removed btoa (which is not required). Then encrypted data is converted to String. suggested by @Topaco in the comments