CryptoJS AES256 decryption issue

i’m experiencing some issues during the decryption of an AES256 encoded URL. For the decryption process im using CryptoJS, however the output throws the following exception:

Malformed UTF-8 data

Did i miss something? Code:

router.post("/signin/:eoLogin2", async (req, res) => {
  const param = req.params.eoLogin2;
  const key = "26kozQaKwRuNJ24tsfd22asdaD2f6232";

  try {
    // 1. DECODE URL, CONVERT DATA AND IV TO BASE64 atob()
    const decodedURL = decodeURI(param);
    const data = atob(decodedURL.split(":")[0]);
    const IV = atob(decodedURL.split(":")[1]);

    console.table(["Base64 decoded DATA: ", data]);
    console.table(["Base64 decoded IV: ", IV]);

    // 2. DECRYPT DATA
    const decrypted = CryptoJS.AES.decrypt(data, key, {
      iv: IV,
      mode: CryptoJS.mode.CBC,
    }).toString(CryptoJS.enc.Utf8);

    console.log(decrypted);

    return;
  } catch (err) {
    console.log(err.message);
    res.status(500).send({ msg: "Internal server error" });
  }
});

URL:

http://localhost:8000/api/v1/users/signin/dwmV7J2tAsk%2F%2F2cU6I1ce8NHtE0D55sXM6GL9eJQe744bp6RQZ2uvhaxa6%2Fvs8m5BtcbFcOpgY%2BpEP3gaKXgVe4QFPLfQTTgB0aeZTvyGOIk%2FdHyF%2B%2FNpZj0jHj6smq5QOyeYf4kZYTzBFxn9YLgZLigYl%2F0gvi1eOq5BMJRhFqKC8T5F9WrtWKhVgynSKT5roQYYRa2xXwNnoQezqx8xtd0BEneWxMN9Tm5XvRHkIOKmoSDD1b5WPAvSWi8%2FdK9%3ANjE3YjVkNjhkNTc0MTI3Mg%3D%3D

Answer

So that the decryption is possible, the following must be changed in the posted code:

  • The key must be UTF8 encoded and parsed into a WordArray.
  • The IV part must be Base64 decoded and parsed into a WordArray.
  • The data part does not need to be Base64 decoded, but can be passed directly as Base64 encoded string to CryptoJS.AES.decrypt().

With these changes the following Crypto-code:

const key = "26kozQaKwRuNJ24tsfd22asdaD2f6232";
const decodedURL = decodeURIComponent("dwmV7J2tAsk%2F%2F2cU6I1ce8NHtE0D55sXM6GL9eJQe744bp6RQZ2uvhaxa6%2Fvs8m5BtcbFcOpgY%2BpEP3gaKXgVe4QFPLfQTTgB0aeZTvyGOIk%2FdHyF%2B%2FNpZj0jHj6smq5QOyeYf4kZYTzBFxn9YLgZLigYl%2F0gvi1eOq5BMJRhFqKC8T5F9WrtWKhVgynSKT5roQYYRa2xXwNnoQezqx8xtd0BEneWxMN9Tm5XvRHkIOKmoSDD1b5WPAvSWi8%2FdK9%3ANjE3YjVkNjhkNTc0MTI3Mg%3D%3D");
const data = decodedURL.split(":")[0];
const IV = decodedURL.split(":")[1];
const decrypted = CryptoJS.AES.decrypt(
      data,     
      CryptoJS.enc.Utf8.parse(key), 
      {
          iv: CryptoJS.enc.Base64.parse(IV),
          mode: CryptoJS.mode.CBC
      }).toString(CryptoJS.enc.Utf8)

console.log(decrypted.replace(/(.{56})/g,'$1n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

successfully decrypts the ciphertext.

The plaintext is:

userName=SEIDLTot1;userPass=3CB5DE262A55F5A21083AB2B9DC07367E01EC61CB81F849D4EBC024BC0E75F1650F8B11815D0AC77B8450DCC62300145B1A083FA70F64857134882854CAE481B;sendTime=1605287468

Further details, e.g. about the encoders, are described in the CryptoJS-documentation, here.