Search code examples
javascriptencryptioncryptojs

CryptoJS decryption Malformed UTF-8 data error


I tried to encrypt and decrypt object. Encryption is working fine ,it turns encrypted string. But description function always returned me "Malformed UTF-8 data error"

Object

var data = {
        'City': 1,
        'DisplayOrder': 20,
        'Semantic': [{'Value': '1','Description': [{'value': 'string'}],
        'aff': [{'Id': '2','Name': 'Feature1','FeatureOptions': [{'Key': 'Key1','Value': 'Value1'},{    'Key': 'Key2','Value': 'Value2'}],
        'SelectedFeatureOption': {    'Key': 'Key1',    'Value': 'Value1'}}],'aff1': [{'Key': 'Key1','Value':'Value1'}]
        }]
    }

Encrypt

function encryptData2(data) {
var Key = C.enc.Utf8.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");
        var IV = CryptoJS.enc.Utf8.parse("0123456789ABCDEF");
        var encryptedText = CryptoJS.AES.encrypt(JSON.stringify(data), Key, {
            iv: IV,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encryptedText.toString(CryptoJS.format.Hex);
    }
    var encryptedData = encryptData2(data);

Decrypt

 var decryptData2 = function(encryptedData, key) {
        var C = CryptoJS;
        encryptedData = C.enc.Base64.parse(encryptedData);
var Key = C.enc.Utf8.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");
        var IV = C.enc.Utf8.parse("0123456789ABCDEF");
        var decryptedText = C.AES.encrypt(encryptedData, Key, {
            iv: IV,
            mode: C.mode.CBC,
            padding: C.pad.Pkcs7
        });
        return encryptedData.toString(CryptoJS.enc.Utf8)
    }

    var result = decryptData2(encryptedData);

How to resolve it ?


Solution

  • Since both, the encrypt- and decrypt-method process various data types (see The Cipher Input and The Cipher Output), there are several ways to solve the incompatibilities between encryptData2 and decryptData2. One possibility is:

    const CryptoJS = require("crypto-js");
    
    var data = {
        'City': 1,
        'DisplayOrder': 20,
        'Semantic': [{'Value': '1','Description': [{'value': 'string'}],
        'aff': [{'Id': '2','Name': 'Feature1','FeatureOptions': [{'Key': 'Key1','Value': 'Value1'},{    'Key': 'Key2','Value': 'Value2'}],
        'SelectedFeatureOption': {    'Key': 'Key1',    'Value': 'Value1'}}],'aff1': [{'Key': 'Key1','Value':'Value1'}]
        }]
    }
    
    function encryptData2(data) {
        //var Key = C.enc.Utf8.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");
        var Key = CryptoJS.enc.Utf8.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");  // 1. Replace C by CryptoJS
        var IV = CryptoJS.enc.Utf8.parse("0123456789ABCDEF");
        var encryptedText = CryptoJS.AES.encrypt(JSON.stringify(data), Key, {
            iv: IV,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        //return encryptedText.toString(CryptoJS.format.Hex);
        return encryptedText.toString(CryptoJS.format.Base64);                              // 2. Use Base64 instead of Hex
    }
    var encryptedData = encryptData2(data);
    
    var decryptData2 = function(encryptedData, key) {
        var C = CryptoJS;
        //encryptedData = C.enc.Base64.parse(encryptedData);                                // 3. Remove line
        var Key = C.enc.Utf8.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");
        var IV = C.enc.Utf8.parse("0123456789ABCDEF");
        //var decryptedText = C.AES.encrypt(encryptedData, Key, {
        var decryptedText = C.AES.decrypt(encryptedData, Key, {                             // 4. Use decrypt instead of encrypt
            iv: IV,
            mode: C.mode.CBC,
            padding: C.pad.Pkcs7
        });
        //return encryptedData.toString(CryptoJS.enc.Utf8);
        return decryptedText.toString(CryptoJS.enc.Utf8);                                   // 5. Use decryptedText instead of encryptedData
    }
    
    var result = decryptData2(encryptedData);
    console.log(result); 
    

    As a side note, the key seems to be Base64-encoded, so it is best parsed this way:

    var Key = CryptoJS.enc.Base64.parse("6il7YCRSqIOB9NooY225lPKQ0KuAF/nkFX6cY3vJkS0=");
    

    Update:

    Following @kelalaka's suggestion, decryptData2 should normally return a JSON object, since a JSON object is also passed to encryptData2. In this case, the JSON string in decryptData2 would have to be converted into a JSON object when it is returned, e.g. with:

    return JSON.parse(decryptedText.toString(CryptoJS.enc.Utf8));