Does sjcl support arraybuffers?

255 views Asked by At

I'm trying to use sjcl to encrypt and then decrypt an arraybuffer. I can see in the source that sjcl has a codec for arraybuffer but I just can't figure out how to use it:

const buffer = new ArrayBuffer(64);
const view = new Uint8Array(buffer);
console.log(view.length)
var encrypted = sjcl.encrypt("password", buffer)
console.log(encrypted.length)
var decrypted = sjcl.decrypt("password", encrypted)
console.log(decrypted.length)    

The first console.log() prints 64 (which makes sense). The second console.log() prints 150 (the size of the encrypted results)... But the third console.log always prints 0.

2

There are 2 answers

1
obscure On

The usage and documentation on sjcl is as cryptic as it's purpose but what you want to achieve is possible of course.

First you have to use the arrayBufferCodec codec to translate your ArrayBuffer to sjcl's own internal bitArray representation. Afterwards this needs to be translated once more to a Base64 string which can be fed to the sjcl.encrypt() method. The reverse of this procedure will give you back your original ArrayBuffer.

Here's an example:

var buffer = new ArrayBuffer(64);
var view = new Uint8Array(buffer);

for (var i = 0; i < view.length; i++) {
  view[i] = i;
}

var arrayBufferBits = sjcl.codec.arrayBuffer.toBits(buffer);
var base64String = sjcl.codec.base64.fromBits(arrayBufferBits);
var encrypted = sjcl.encrypt("password", base64String);

var decrypted = sjcl.decrypt("password", encrypted);
var base64Bits = sjcl.codec.base64.toBits(decrypted);
var buffer2 = sjcl.codec.arrayBuffer.fromBits(base64Bits);

view = new Uint8Array(buffer2);
console.log(view);
<script type="text/javascript" src="https://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/core/codecArrayBuffer.js"></script>

0
Ningshan Li On

As pointed out by @Neneil, answer from @obscure try to use sjcl.codec.arrayBuffer.toBits to convert an ArrayBuffer to sjcl's bitArray. Based on the documentation of sjcl.codec.arrayBuffer, it has only two methods fromBits() and hexDumpBuffer(), and no method named toBits() is defined in old version, that is why @Neneil encounter the error TypeError: undefined is not an object (evaluating '_sjcl.default.codec.arrayBuffer.toBits'). In the latest version 1.0.8, toBits() has been defined.

To encrypt and then decrypt an ArrayBuffer, another way is just working on TypedArrays without converting to plain text, though under the context of encryption and decryption plain text is expected.

Detailed steps are:

  1. first create an Uint8Array backed by the ArrayBuffer,
  2. then further covert the TypedArray to sjcl's bitArray by sjcl.codec.bytes.toBits(), since sjcl does all computation on bitArrays.
  3. Next use sjcl.encrypt() to encrypt it.
  4. For decryption, use TextEncoder to convert the decryped plain text to a stream of UTF-8 bytes, and the ArrayBuffer associated with this Uint8Array can be accessed using the buffer property.

Here is an example:

const buffer = new ArrayBuffer(64);
let view = new Uint8Array(buffer);

for (var i = 0; i < view.length; i++) {
  view[i] = i;
}

const sjcl_bits = sjcl.codec.bytes.toBits(view);
const encrypted = sjcl.encrypt("password", sjcl_bits);

const decrypted = sjcl.decrypt("password", encrypted);
const decrypted_uint8Array = new TextEncoder('utf-8').encode(decrypted);

console.log(decrypted_uint8Array);

// access the associated ArrayBuffer using buffer property
const decryped_buffer = decrypted_uint8Array.buffer;
<script src="https://cdn.jsdelivr.net/npm/[email protected]/sjcl.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/core/codecBytes.min.js"></script>