javascriptaescryptojs

Splitting CryptoJS word array to extract the IV before decryption


I receive a base64 encoded string. The first 16 bytes are the IV. I need to extract them before I decrypt with CryptoJS.

I am failing to split data from CryptoJS.enc.Base64.parse

In a nutshell, please help me fill this:

/*
 * ivAndcipheredDataBase64: first 16 bytes are iv the rest is the cipheredData
 */
function decipherData(ivAndcipheredDataBase64, key) {

    var ivAndCipheredDataBytes = CryptoJS.enc.Base64.parse(ivAndcipheredDataBase64);
    var iv = // What do I put here to get cipheredIVAndDataBytes[0:16]
    var cipheredData = // What do I put here to get cipheredIVAndDataBytes[16:len(cipheredIVAndDataBytes)]
   

    var plainDataBytes = CryptoJS.AES.decrypt({ ciphertext: cipheredData }, key, {
        iv: iv
    });
    return plainDataBytes.toString(CryptoJS.enc.Utf8)

}

Thanks, I am having trouble to know the type returned by CryptoJS.enc.Base64.parse, the documentation says WordArray object but i am not sure how to deal with that


Solution

  • A WordArray contains an array (called words) of words. Each word in words contains 4 bytes of data. The number of significant data bytes is stored in sigBytes. Example:

    var data = CryptoJS.lib.WordArray.create([0x6a757374, 0x20612074, 0x6573746d, 0x65737361, 0x67650123], 18); // a WordArray with 5*4=20 bytes; the last 2 bytes are ignored because sigBytes = 18
    console.log(data.toString())
    console.log(data.toString(CryptoJS.enc.Utf8))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>

    If the data is a multiple of 4 bytes, sigBytes does not need to be specified. All bytes are then taken into account.


    To solve your problem, you need to create a WordArray for each IV and ciphertext with CryptoJS.lib.WordArray.create() and slice IV and ciphertext from the words array of the WordArray of the concatenated data:

    ...
    var ivAndCipheredDataBytes = CryptoJS.enc.Base64.parse(ivAndcipheredDataBase64);
    var iv = CryptoJS.lib.WordArray.create(ivAndCipheredDataBytes.words.slice(0, 4));    // iv: first 4 words = 16 bytes
    var ct = CryptoJS.lib.WordArray.create(ivAndCipheredDataBytes.words.slice(4));       // ciphertext: rest 
    ...
    

    Since both IV (for AES 16 bytes) and ciphertext (for AES/CBC a multiple of the block size of 16 bytes) are multiples of 4 bytes, the specification of sigBytes is not required.