Skip to content

Instantly share code, notes, and snippets.

@getify
Last active October 26, 2023 04:04
Show Gist options
  • Select an option

  • Save getify/7325764 to your computer and use it in GitHub Desktop.

Select an option

Save getify/7325764 to your computer and use it in GitHub Desktop.
converting between Uint8Arrays and binary-encoded strings and word-arrays (for crypto purposes, with CryptoJS and NaCL)
/*
wordArray: { words: [..], sigBytes: words.length * 4 }
*/
// assumes wordArray is Big-Endian (because it comes from CryptoJS which is all BE)
// From: https://gist.github.com/creationix/07856504cf4d5cede5f9#file-encode-js
function convertWordArrayToUint8Array(wordArray) {
var len = wordArray.words.length,
u8_array = new Uint8Array(len << 2),
offset = 0, word, i
;
for (i=0; i<len; i++) {
word = wordArray.words[i];
u8_array[offset++] = word >> 24;
u8_array[offset++] = (word >> 16) & 0xff;
u8_array[offset++] = (word >> 8) & 0xff;
u8_array[offset++] = word & 0xff;
}
return u8_array;
}
// create a wordArray that is Big-Endian (because it's used with CryptoJS which is all BE)
// From: https://gist.github.com/creationix/07856504cf4d5cede5f9#file-encode-js
function convertUint8ArrayToWordArray(u8Array) {
var words = [], i = 0, len = u8Array.length;
while (i < len) {
words.push(
(u8Array[i++] << 24) |
(u8Array[i++] << 16) |
(u8Array[i++] << 8) |
(u8Array[i++])
);
}
return {
sigBytes: words.length * 4,
words: words
};
}
function convertUint8ArrayToBinaryString(u8Array) {
var i, len = u8Array.length, b_str = "";
for (i=0; i<len; i++) {
b_str += String.fromCharCode(u8Array[i]);
}
return b_str;
}
function convertBinaryStringToUint8Array(bStr) {
var i, len = bStr.length, u8_array = new Uint8Array(len);
for (var i = 0; i < len; i++) {
u8_array[i] = bStr.charCodeAt(i);
}
return u8_array;
}
@creationix

Copy link
Copy Markdown

For converting a Uint32Array to a normal Array, you can use the old Array.prototype.slice.call(arrayLike) trick.

@getify

getify commented Nov 5, 2013

Copy link
Copy Markdown
Author

@creationix are you talking about these lines?

@creationix

Copy link
Copy Markdown

Right.

w_array = {
  sigBytes: len,
  words: Array.prototype.slice.call(u32_array)
};

@getify

getify commented Nov 5, 2013

Copy link
Copy Markdown
Author

@creationix thanks, updated!

@getify

getify commented Nov 6, 2013

Copy link
Copy Markdown
Author

NOTE: had to update the gist to account for Big-Endianess coming out of CryptoJS lib (in its WordArray instances). Uint32Array instances subjected that data to a platform-dependent assumption of endianess, which was possibly unsafe. The above now goes directly from the explicitly (not assumed) BE of the WordArray to a non-endian Uint8Array (and vice versa).

@hygroovy

Copy link
Copy Markdown

convertWordArrayToUint8Array was creating an array that was slightly longer than the original wordarray for me. I replaced -
var len = wordArray.words.length, u8_array = new Uint8Array(len << 2),
with
u8_array = new Uint8Array(wordArray.sigBytes)
and this seems to have corrected the issue.

@pawelabrams

pawelabrams commented Nov 30, 2016

Copy link
Copy Markdown

CryptoJS's WordArray has sigBytes for cases when length of uint8array is not divisible by 4. It should be the length of the original array and signals how much of the last word should be used.

This was also the source of @hygroovy's problem. Funfact: we're discussing this under a three-year-old topic :P

ghost commented Mar 27, 2020

Copy link
Copy Markdown

Thanks , Mr. Simpson. these help me a lot when play with msgpack and axios.

@tomer8007

Copy link
Copy Markdown

@pawelabrams Right, this caused troubles for me and should be changed to sigBytes: len

@misaon

misaon commented Jan 14, 2022

Copy link
Copy Markdown

Big thanks for inspiration!

@asins

asins commented Oct 26, 2023

Copy link
Copy Markdown
const formatU8Afrom = Uint8Array.from.bind(Uint8Array);

const formatFromCC = String.fromCharCode.bind(String);

export function stringToUint8Array(str: string) {
  return formatU8Afrom(str, (c) => c.charCodeAt(0));
}

export function uint8ArrayToString(u8a: Uint8Array) {
  // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326
  const maxargs = 0x1000;
  const strs = [];
  for (let i = 0, l = u8a.length; i < l; i += maxargs) {
    strs.push(formatFromCC(...u8a.subarray(i, i + maxargs)));
  }
  return strs.join('');
}

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