diff --git a/www/file/file-crypto.js b/www/file/file-crypto.js index 35e2f8037..5290dfb80 100644 --- a/www/file/file-crypto.js +++ b/www/file/file-crypto.js @@ -57,55 +57,30 @@ define([ }, [])); }; - var padChunk = function (A) { - var padding; - if (A.length === plainChunkLength) { return A; } - if (A.length < plainChunkLength) { - padding = new Array(plainChunkLength - A.length).fill(32); - return A.concat(padding); - } - if (A.length > plainChunkLength) { - // how many times larger is it? - var chunks = Math.ceil(A.length / plainChunkLength); - padding = new Array((plainChunkLength * chunks) - A.length).fill(32); - return A.concat(padding); - } - }; - var decrypt = function (u8, key, cb) { + var fail = function (e) { + cb(e || "DECRYPTION_ERROR"); + }; + var nonce = createNonce(); var i = 0; - decodePrefix([]); // TODO - var takeChunk = function () { - var start = i * cypherChunkLength; - var end = start + cypherChunkLength; - i++; - var box = new Uint8Array(u8.subarray(start, end)); - - // decrypt the chunk - var plaintext = Nacl.secretbox.open(box, nonce, key); - increment(nonce); - return plaintext; - }; - - var buffer = ''; + var prefix = u8.subarray(0, 2); + var metadataLength = decodePrefix(prefix); var res = { metadata: undefined, }; - // decrypt metadata - var chunk; - for (; !res.metadata && i * cypherChunkLength < u8.length;) { - chunk = takeChunk(); - buffer += Nacl.util.encodeUTF8(chunk); - try { - res.metadata = JSON.parse(buffer); - //console.log(res.metadata); - } catch (e) { - console.log('buffering another chunk for metadata'); - } + var metaBox = new Uint8Array(u8.subarray(2, 2 + metadataLength)); + + var metaChunk = Nacl.secretbox.open(metaBox, nonce, key); + increment(nonce); + + try { + res.metadata = JSON.parse(Nacl.util.encodeUTF8(metaChunk)); + } catch (e) { + return fail('E_METADATA_DECRYPTION'); } if (!res.metadata) { @@ -114,12 +89,21 @@ define([ }); } - var fail = function () { - cb("DECRYPTION_ERROR"); + var takeChunk = function () { + var start = i * cypherChunkLength + 2 + metadataLength; + var end = start + cypherChunkLength; + i++; + var box = new Uint8Array(u8.subarray(start, end)); + + // decrypt the chunk + var plaintext = Nacl.secretbox.open(box, nonce, key); + increment(nonce); + return plaintext; }; var chunks = []; // decrypt file contents + var chunk; for (;i * cypherChunkLength < u8.length;) { chunk = takeChunk(); if (!chunk) { @@ -139,15 +123,12 @@ define([ var encrypt = function (u8, metadata, key) { var nonce = createNonce(); - encodePrefix(); // TODO - // encode metadata var metaBuffer = Array.prototype.slice .call(Nacl.util.decodeUTF8(JSON.stringify(metadata))); - var plaintext = new Uint8Array(padChunk(metaBuffer)); + var plaintext = new Uint8Array(metaBuffer); - var j = 0; var i = 0; /* @@ -164,22 +145,21 @@ define([ var part; var box; - if (state === 0) { // metadata... - start = j * plainChunkLength; - end = start + plainChunkLength; + // DONE + if (state === 2) { return void cb(); } - part = plaintext.subarray(start, end); + if (state === 0) { // metadata... + part = new Uint8Array(plaintext); box = Nacl.secretbox(part, nonce, key); increment(nonce); - j++; - - // metadata is done - if (j * plainChunkLength >= plaintext.length) { - return void cb(state++, box); + if (box.length > 65535) { + return void cb('METADATA_TOO_LARGE'); } - - return void cb(state, box); + var prefixed = new Uint8Array(encodePrefix(box.length) + .concat(slice(box))); + state++; + return void cb(void 0, prefixed); } // encrypt the rest of the file... @@ -194,7 +174,7 @@ define([ // regular data is done if (i * plainChunkLength >= u8.length) { state = 2; } - return void cb(state, box); + return void cb(void 0, box); }; return next; diff --git a/www/file/main.js b/www/file/main.js index 66e0f6c25..32bcaafe6 100644 --- a/www/file/main.js +++ b/www/file/main.js @@ -47,55 +47,43 @@ define([ }); }; - var again = function (state, box) { - switch (state) { - case 0: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - next(again); - }); - break; - case 1: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - next(again); - }); - break; - case 2: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - Cryptpad.rpc.send('UPLOAD_COMPLETE', '', function (e, res) { - if (e) { return void console.error(e); } - var id = res[0]; - var uri = ['', 'blob', id.slice(0,2), id].join('/'); - console.log("encrypted blob is now available as %s", uri); - - var b64Key = Nacl.util.encodeBase64(key); - window.location.hash = Cryptpad.getFileHashFromKeys(id, b64Key); - - $form.hide(); - - APP.toolbar.addElement(['fileshare'], {}); - - // check if the uploaded file can be decrypted - var newU8 = FileCrypto.joinChunks(chunks); - FileCrypto.decrypt(newU8, key, function (e, res) { - if (e) { return console.error(e); } - var title = document.title = res.metadata.name; - myFile = res.content; - myDataType = res.metadata.type; - - var defaultName = Cryptpad.getDefaultName(Cryptpad.parsePadUrl(window.location.href)); - Title.updateTitle(title || defaultName); - APP.toolbar.title.show(); - Cryptpad.alert("successfully uploaded: " + title); - }); - }); - }); - break; - default: - throw new Error("E_INVAL_STATE"); + var again = function (err, box) { + if (err) { throw new Error(err); } + if (box) { + return void sendChunk(box, function (e) { + if (e) { return console.error(e); } + next(again); + }); } + + // if not box then done + Cryptpad.rpc.send('UPLOAD_COMPLETE', '', function (e, res) { + if (e) { return void console.error(e); } + var id = res[0]; + var uri = ['', 'blob', id.slice(0,2), id].join('/'); + console.log("encrypted blob is now available as %s", uri); + + var b64Key = Nacl.util.encodeBase64(key); + window.location.hash = Cryptpad.getFileHashFromKeys(id, b64Key); + + $form.hide(); + + APP.toolbar.addElement(['fileshare'], {}); + + // check if the uploaded file can be decrypted + var newU8 = FileCrypto.joinChunks(chunks); + FileCrypto.decrypt(newU8, key, function (e, res) { + if (e) { return console.error(e); } + var title = document.title = res.metadata.name; + myFile = res.content; + myDataType = res.metadata.type; + + var defaultName = Cryptpad.getDefaultName(Cryptpad.parsePadUrl(window.location.href)); + Title.updateTitle(title || defaultName); + APP.toolbar.title.show(); + Cryptpad.alert("successfully uploaded: " + title); + }); + }); }; Cryptpad.rpc.send('UPLOAD_STATUS', '', function (e, pending) { diff --git a/www/file/test/main.js b/www/file/test/main.js index c2b24e4f2..5ec71126d 100644 --- a/www/file/test/main.js +++ b/www/file/test/main.js @@ -11,7 +11,6 @@ define([ '/bower_components/file-saver/FileSaver.min.js', ], function ($, Crypto, realtimeInput, Toolbar, Cryptpad, Visible, Notify, FileCrypto) { var Nacl = window.nacl; - $(function () { var filesAreSame = function (a, b) { @@ -31,8 +30,8 @@ define([ var upload = function (blob, metadata) { var u8 = new Uint8Array(blob); - var key = Nacl.randomBytes(32); + var next = FileCrypto.encrypt(u8, metadata, key); var chunks = []; @@ -41,41 +40,32 @@ define([ cb(); }; - var again = function (state, box) { - switch (state) { - case 0: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - next(again); - }); - break; - case 1: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - next(again); - }); - break; - case 2: - sendChunk(box, function (e) { - if (e) { return console.error(e); } - - // check if the uploaded file can be decrypted - var newU8 = FileCrypto.joinChunks(chunks); - FileCrypto.decrypt(newU8, key, function (e, res) { - if (e) { return Cryptpad.alert(e); } + var again = function (err, box) { + if (err) { throw new Error(err); } - if (filesAreSame(blob, res.content) && - metadataIsSame(res.metadata, metadata)) { - Cryptpad.alert("successfully uploaded"); - } else { - Cryptpad.alert('encryption failure!'); - } - }); - }); - break; - default: - throw new Error("E_INVAL_STATE"); + if (box) { + return void sendChunk(box, function (e) { + if (e) { + console.error(e); + return Cryptpad.alert('Something went wrong'); + } + next(again); + }); } + // check if the uploaded file can be decrypted + var newU8 = FileCrypto.joinChunks(chunks); + + console.log('encrypted file with metadata is %s uint8s', newU8.length); + FileCrypto.decrypt(newU8, key, function (e, res) { + if (e) { return Cryptpad.alert(e); } + + if (filesAreSame(blob, res.content) && + metadataIsSame(res.metadata, metadata)) { + Cryptpad.alert("successfully uploaded"); + } else { + Cryptpad.alert('encryption failure!'); + } + }); }; next(again); }; @@ -83,7 +73,7 @@ define([ var andThen = function () { var src = '/customize/cryptofist_mini.png'; Cryptpad.fetch(src, function (e, file) { - console.log(file); + console.log('original file is %s uint8s', file.length); upload(file, { pew: 'pew', bang: 'bang',