new encrypted file format
This commit is contained in:
parent
8f5989b6b0
commit
1525712deb
3 changed files with 104 additions and 146 deletions
|
@ -57,28 +57,40 @@ 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 decrypt = function (u8, key, cb) {
|
||||||
|
var fail = function (e) {
|
||||||
|
cb(e || "DECRYPTION_ERROR");
|
||||||
|
};
|
||||||
|
|
||||||
var nonce = createNonce();
|
var nonce = createNonce();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
decodePrefix([]); // TODO
|
var prefix = u8.subarray(0, 2);
|
||||||
|
var metadataLength = decodePrefix(prefix);
|
||||||
|
|
||||||
|
var res = {
|
||||||
|
metadata: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return void setTimeout(function () {
|
||||||
|
cb('NO_METADATA');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var takeChunk = function () {
|
var takeChunk = function () {
|
||||||
var start = i * cypherChunkLength;
|
var start = i * cypherChunkLength + 2 + metadataLength;
|
||||||
var end = start + cypherChunkLength;
|
var end = start + cypherChunkLength;
|
||||||
i++;
|
i++;
|
||||||
var box = new Uint8Array(u8.subarray(start, end));
|
var box = new Uint8Array(u8.subarray(start, end));
|
||||||
|
@ -89,37 +101,9 @@ define([
|
||||||
return plaintext;
|
return plaintext;
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer = '';
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res.metadata) {
|
|
||||||
return void setTimeout(function () {
|
|
||||||
cb('NO_METADATA');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function () {
|
|
||||||
cb("DECRYPTION_ERROR");
|
|
||||||
};
|
|
||||||
|
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
// decrypt file contents
|
// decrypt file contents
|
||||||
|
var chunk;
|
||||||
for (;i * cypherChunkLength < u8.length;) {
|
for (;i * cypherChunkLength < u8.length;) {
|
||||||
chunk = takeChunk();
|
chunk = takeChunk();
|
||||||
if (!chunk) {
|
if (!chunk) {
|
||||||
|
@ -139,15 +123,12 @@ define([
|
||||||
var encrypt = function (u8, metadata, key) {
|
var encrypt = function (u8, metadata, key) {
|
||||||
var nonce = createNonce();
|
var nonce = createNonce();
|
||||||
|
|
||||||
encodePrefix(); // TODO
|
|
||||||
|
|
||||||
// encode metadata
|
// encode metadata
|
||||||
var metaBuffer = Array.prototype.slice
|
var metaBuffer = Array.prototype.slice
|
||||||
.call(Nacl.util.decodeUTF8(JSON.stringify(metadata)));
|
.call(Nacl.util.decodeUTF8(JSON.stringify(metadata)));
|
||||||
|
|
||||||
var plaintext = new Uint8Array(padChunk(metaBuffer));
|
var plaintext = new Uint8Array(metaBuffer);
|
||||||
|
|
||||||
var j = 0;
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,22 +145,21 @@ define([
|
||||||
var part;
|
var part;
|
||||||
var box;
|
var box;
|
||||||
|
|
||||||
if (state === 0) { // metadata...
|
// DONE
|
||||||
start = j * plainChunkLength;
|
if (state === 2) { return void cb(); }
|
||||||
end = start + plainChunkLength;
|
|
||||||
|
|
||||||
part = plaintext.subarray(start, end);
|
if (state === 0) { // metadata...
|
||||||
|
part = new Uint8Array(plaintext);
|
||||||
box = Nacl.secretbox(part, nonce, key);
|
box = Nacl.secretbox(part, nonce, key);
|
||||||
increment(nonce);
|
increment(nonce);
|
||||||
|
|
||||||
j++;
|
if (box.length > 65535) {
|
||||||
|
return void cb('METADATA_TOO_LARGE');
|
||||||
// metadata is done
|
|
||||||
if (j * plainChunkLength >= plaintext.length) {
|
|
||||||
return void cb(state++, box);
|
|
||||||
}
|
}
|
||||||
|
var prefixed = new Uint8Array(encodePrefix(box.length)
|
||||||
return void cb(state, box);
|
.concat(slice(box)));
|
||||||
|
state++;
|
||||||
|
return void cb(void 0, prefixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt the rest of the file...
|
// encrypt the rest of the file...
|
||||||
|
@ -194,7 +174,7 @@ define([
|
||||||
// regular data is done
|
// regular data is done
|
||||||
if (i * plainChunkLength >= u8.length) { state = 2; }
|
if (i * plainChunkLength >= u8.length) { state = 2; }
|
||||||
|
|
||||||
return void cb(state, box);
|
return void cb(void 0, box);
|
||||||
};
|
};
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
|
@ -47,55 +47,43 @@ define([
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var again = function (state, box) {
|
var again = function (err, box) {
|
||||||
switch (state) {
|
if (err) { throw new Error(err); }
|
||||||
case 0:
|
if (box) {
|
||||||
sendChunk(box, function (e) {
|
return void sendChunk(box, function (e) {
|
||||||
if (e) { return console.error(e); }
|
if (e) { return console.error(e); }
|
||||||
next(again);
|
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
Cryptpad.rpc.send('UPLOAD_STATUS', '', function (e, pending) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ define([
|
||||||
'/bower_components/file-saver/FileSaver.min.js',
|
'/bower_components/file-saver/FileSaver.min.js',
|
||||||
], function ($, Crypto, realtimeInput, Toolbar, Cryptpad, Visible, Notify, FileCrypto) {
|
], function ($, Crypto, realtimeInput, Toolbar, Cryptpad, Visible, Notify, FileCrypto) {
|
||||||
var Nacl = window.nacl;
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
var filesAreSame = function (a, b) {
|
var filesAreSame = function (a, b) {
|
||||||
|
@ -31,8 +30,8 @@ define([
|
||||||
|
|
||||||
var upload = function (blob, metadata) {
|
var upload = function (blob, metadata) {
|
||||||
var u8 = new Uint8Array(blob);
|
var u8 = new Uint8Array(blob);
|
||||||
|
|
||||||
var key = Nacl.randomBytes(32);
|
var key = Nacl.randomBytes(32);
|
||||||
|
|
||||||
var next = FileCrypto.encrypt(u8, metadata, key);
|
var next = FileCrypto.encrypt(u8, metadata, key);
|
||||||
|
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
|
@ -41,41 +40,32 @@ define([
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
var again = function (state, box) {
|
var again = function (err, box) {
|
||||||
switch (state) {
|
if (err) { throw new Error(err); }
|
||||||
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
|
if (box) {
|
||||||
var newU8 = FileCrypto.joinChunks(chunks);
|
return void sendChunk(box, function (e) {
|
||||||
FileCrypto.decrypt(newU8, key, function (e, res) {
|
if (e) {
|
||||||
if (e) { return Cryptpad.alert(e); }
|
console.error(e);
|
||||||
|
return Cryptpad.alert('Something went wrong');
|
||||||
if (filesAreSame(blob, res.content) &&
|
}
|
||||||
metadataIsSame(res.metadata, metadata)) {
|
next(again);
|
||||||
Cryptpad.alert("successfully uploaded");
|
});
|
||||||
} else {
|
|
||||||
Cryptpad.alert('encryption failure!');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("E_INVAL_STATE");
|
|
||||||
}
|
}
|
||||||
|
// 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);
|
next(again);
|
||||||
};
|
};
|
||||||
|
@ -83,7 +73,7 @@ define([
|
||||||
var andThen = function () {
|
var andThen = function () {
|
||||||
var src = '/customize/cryptofist_mini.png';
|
var src = '/customize/cryptofist_mini.png';
|
||||||
Cryptpad.fetch(src, function (e, file) {
|
Cryptpad.fetch(src, function (e, file) {
|
||||||
console.log(file);
|
console.log('original file is %s uint8s', file.length);
|
||||||
upload(file, {
|
upload(file, {
|
||||||
pew: 'pew',
|
pew: 'pew',
|
||||||
bang: 'bang',
|
bang: 'bang',
|
||||||
|
|
Loading…
Reference in a new issue