Search code examples
javascriptnode.jsbase64aescryptojs

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

Solution

  • 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,'$1\n'));
    <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.