Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypting files with SJCL client-side

I have problem encrypting files with SJCL and javascript.

I have managed to encrypt text-files with using FileReader API and readAsBinaryString. When it comes to encrypting pdf/png/.. then problem arrises probably due to encoding.

I found that I can use readAsArrayBuffer which suits this task perfectly, so I basically read file and create new typed array with new Uint8Array() but i dont know how exactly I am supposed to encrypt such a data.

Here's my code:

/** Convert from an array of bytes to a bitArray. */
function toBitArrayCodec(bytes) {
    var out = [], i, tmp=0;
    for (i=0; i<bytes.length; i++) {
        tmp = tmp << 8 | bytes[i];
        if ((i&3) === 3) {
            out.push(tmp);
            tmp = 0;
        }
    }
    if (i&3) {
        out.push(sjcl.bitArray.partial(8*(i&3), tmp));
    }
    return out;
}

/** Convert from a bitArray to an array of bytes. */
function fromBitArrayCodec(arr) {
    var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp;
    for (i=0; i<bl/8; i++) {
        if ((i&3) === 0) {
            tmp = arr[i/4];
        }
        out.push(tmp >>> 24);
        tmp <<= 8;
    }
    return out;
}

var reader = new FileReader();
    reader.readAsArrayBuffer(fileData); //filedata comes from function
    reader.onload = function() {
        var bytes = new Uint8Array(reader.result);
        var bits = toBitArrayCodec(bytes);
        var crypt = sjcl.encrypt("aaaaa", bits);

        var decrypt = sjcl.decrypt("aaaaa", crypt);
        var byteNumbers = fromBitArrayCodec(decrypt);
        var byteArray = new Uint8Array(byteNumbers);
        saveData(byteArray, 'png.png');

I am getting error on

Uncaught URIError: URI malformed sjcl.js:12sjcl.codec.utf8String.fromBits sjcl.js:12sjcl.json.decrypt sjcl.js:44reader.onload

I need to know how to encrypt uint8array or another alternative how to encrypt(pdf/png/..) files.

like image 913
Yetti Avatar asked Nov 04 '14 11:11

Yetti


1 Answers

The plaintext in sjcl is expected to be utf8 encoded. Encrypting a manually built bitArray works, because the encryption is done on the bitArray and it doesn't have to be decoded. But at the end of the decryption is an encoding step which converts the recovered plaintext bitArray into a utf8string. This doesn't work, because it contains unprintable characters, because the source was probably binary.

The solution would be to encode it as Base64 before encrypting and convert it back after decrypting.

var bytes = new Uint8Array(reader.result);
var bits = toBitArrayCodec(bytes);
var base64bits = sjcl.codec.base64.fromBits(bits); // added
var crypt = sjcl.encrypt("aaaaa", base64bits);

var base64decrypt = sjcl.decrypt("aaaaa", crypt);
var decrypt = sjcl.codec.base64.toBits(base64decrypt); // added
var byteNumbers = fromBitArrayCodec(decrypt);
var byteArray = new Uint8Array(byteNumbers);
like image 76
Artjom B. Avatar answered Oct 16 '22 12:10

Artjom B.