Skip to content

Instantly share code, notes, and snippets.

@artjomb
Last active January 9, 2024 16:43
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save artjomb/7ef1ee574a411ba0dd1933c1ef4690d1 to your computer and use it in GitHub Desktop.
Save artjomb/7ef1ee574a411ba0dd1933c1ef4690d1 to your computer and use it in GitHub Desktop.
Convert a byte array to a word array and back in CryptoJS-compatible fashion
function byteArrayToWordArray(ba) {
var wa = [],
i;
for (i = 0; i < ba.length; i++) {
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
}
return CryptoJS.lib.WordArray.create(wa, ba.length);
}
function wordToByteArray(word, length) {
var ba = [],
i,
xFF = 0xFF;
if (length > 0)
ba.push(word >>> 24);
if (length > 1)
ba.push((word >>> 16) & xFF);
if (length > 2)
ba.push((word >>> 8) & xFF);
if (length > 3)
ba.push(word & xFF);
return ba;
}
function wordArrayToByteArray(wordArray, length) {
if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) {
length = wordArray.sigBytes;
wordArray = wordArray.words;
}
var result = [],
bytes,
i = 0;
while (length > 0) {
bytes = wordToByteArray(wordArray[i], Math.min(4, length));
length -= bytes.length;
result.push(bytes);
i++;
}
return [].concat.apply([], result);
}
@mahmoud-samy
Copy link

-1

@1Hyena
Copy link

1Hyena commented May 15, 2018

Bug on line 38: result = result.push(bytes);

should be this instead: result.push(bytes);

@artjomb
Copy link
Author

artjomb commented May 17, 2018

done

@marexv
Copy link

marexv commented Jun 14, 2018

Worked for me. Thank you!

@Udbhav12
Copy link

Worked for me. Thanks a lot !!!

@shyamks
Copy link

shyamks commented Oct 23, 2018

Worked for me. Thanks a lot !

@dinos80152
Copy link

👍
I'll tag this gist in my project :)

@victoryeo
Copy link

victoryeo commented Nov 22, 2018

when convert a word array size of sigBytes of 1189455, i got error of Maximum call stack size exceeded
screen shot 2018-11-22 at 11 38 16 am

@priyanka-latambale
Copy link

right shift left shift oprators not working

@VicEcho
Copy link

VicEcho commented Aug 4, 2019

image
It work for me,Thanks!
And There is a comma missing behind "bytes"

@artjomb
Copy link
Author

artjomb commented Aug 4, 2019

Done. Thanks @VicEcho

@Sathyaish
Copy link

This is hugely helpful. Thanks so much. :-)

Just one thing more. Could you please include the ES6 import statement that resolves the symbol CryptoJS? I am guessing it is:

import CryptoJS from "./locationOf/crypto-js.js";

But I can't be sure.

@Sathyaish
Copy link

Just for anyone else who has the same question as mine, as indicated in the previous post in this thread, here is the answer.

It appears that if you do either of the following ES 6 imports, it fails with different errors:

import CryptoJS from "./locationOf/crypto-js.js"; // fails with import not found: default

import "./locationOf/crypto-js.js"; // fails with ReferenceError: root undefined.

I investigated and found that the issue was that symbol root, which is also the first parameter of the iffy that you find at the beginning of the file crypto-js.js was not being initialized to the window object because the argument this that was being passed to it did not resolve to the window object.

So, as a kludge, which worked for me, I replaced the following line (lines 10 to 13):

else {
	// Global (browser)
	root.CryptoJS = factory();
}

with the following line and it worked.

else {
	// Global (browser)
	window.CryptoJS = factory();
}

@Vardner
Copy link

Vardner commented Nov 4, 2019

thanks, great work

@BadPistol97
Copy link

Maximum call stack size exceeded error too when trying to decrypt a video file
image

image

Can someone help me with this please?

@apurbapokharel
Copy link

Did you find the solution to this range error problem ?

@javadba
Copy link

javadba commented Jul 21, 2020

This is pretty bad and buggy code. See the multiple comments. I will look for something more scalable and less errors

@SwissMaWi
Copy link

SwissMaWi commented Mar 5, 2021

I wrote an unit test for this. This implementation works only for converting Uint8Array to CryptoJS.lib.WordArray and back.
It fails for converting CryptoJS.lib.WordArray to Uint8Array and back, the reverse conversion returns different values. That's really bad.

code:
` // ORIGINAL IMPLEMENTATION

static ba2wa(ba) {
var wa = [],
i;
for (i = 0; i < ba.length; i++) {
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
}

return CryptoJS.lib.WordArray.create(wa, ba.length);

}

private static w2ba(word, length) {
var ba = [],
i,
xFF = 0xFF;
if (length > 0)
ba.push(word >>> 24);
if (length > 1)
ba.push((word >>> 16) & xFF);
if (length > 2)
ba.push((word >>> 8) & xFF);
if (length > 3)
ba.push(word & xFF);

return ba;

}

static wa2ba(wordArray, length) {
if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) {
length = wordArray.sigBytes;
wordArray = wordArray.words;
}

var result = [],
  bytes,
  i = 0;
while (length > 0) {
  bytes = this.w2ba(wordArray[i], Math.min(4, length));
  length -= bytes.length;
  result.push(bytes);
  i++;
}
return [].concat.apply([], result);

}
`

test:
`
it('should convert a large CryptoJS.lib.WordArray to a Uint8Array and back to the same CryptoJS.lib.WordArray',
() => {
// Arrange
const input = CryptoJS.lib.WordArray.random(10);
console.log(JSON.stringify(input.words));

    // Act
    const result1 = WordArrayExtensions.wa2ba(input, null);
    const result2 = WordArrayExtensions.ba2wa(result1);

    // Assert
    expect(result1).toBeDefined();
    expect(result2).toBeDefined();
    expect(result2.words).toEqual(input.words);
  });

`

@whossein
Copy link

thank a lot <3

@julianmetza
Copy link

julianmetza commented Apr 27, 2023

Combined and rewrote the words-to-bytes-function to be a bit faster. Just in case someone needs it.

function cryptArrToByteArr(wordArray) {
        var bytes = new Uint8Array(wordArray.sigBytes);

        var fullwords = wordArray.sigBytes >>> 2; //equal div 4
        var lastbytes = wordArray.sigBytes % 4;

        var word, offs;
        for (var i = 0; i < fullwords; i++) {
                word = wordArray.words[i];
                offs = i<<2;
                bytes[offs] = word >>> 24;
                bytes[offs+1] = (word >>> 16) & 0xFF;
                bytes[offs+2] = (word >>> 8) & 0xFF;
                bytes[offs+3] = word & 0xFF;
        }
        if (lastbytes > 0) {
                word = wordArray.words[fullwords];
                offs = fullwords<<2;
                bytes[offs] = word >>> 24;
                if (length > 1) bytes[offs+1] = (word >>> 16) & 0xFF;
                if (length > 2) bytes[offs+2] = (word >>> 8) & 0xFF;
        }
        return bytes;
}

@shampain6660
Copy link

The above code has errors too, although I definitely prefer its intended efficiency:

     if (lastbytes > 0) {
             word = wordArray.words[fullwords];
             offs = fullwords<<2;
             bytes[offs] = word >>> 24;
             if (lastbytes > 1) bytes[offs+1] = (word >>> 16) & 0xFF;
             if (lastbytes > 2) bytes[offs+2] = (word >>> 8) & 0xFF;
     }

@shampain6660
Copy link

In case anyone comes here looking for a solution, here is what I ended up using:

/** Returns a crypto-JS compatible Word Array, based on the byte array provided */
  static toWordArray(bytes) {
    var words = [];
    for (var j = 0; j < bytes.length; j++) {
      words[(j>>>2)] |= bytes[j] << (24 - (8 * (j%4)));
    }
    return CryptoJS.lib.WordArray.create(words, bytes.length);
  }

  /** Returns a byte array, based on the crypto-JS compatible word array provided */
  static fromWordArray(wordArray) {
    var bytes = new Uint8Array(wordArray.sigBytes);
    for (var j=0; j<wordArray.sigBytes; j++) {
      bytes[j] = (wordArray.words[(j>>>2)] >>> (24 - (8 * (j%4)))) & 0xFF
    }
    return bytes;
  }    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment