From 34c367c49f4a7651c1d553f388eb4f26f9baa575 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Tue, 20 Jun 2017 14:33:28 -0700 Subject: [PATCH] added aad encryption --- frontend/src/fileReceiver.js | 8 ++++++-- frontend/src/fileSender.js | 5 ++++- frontend/src/utils.js | 8 +++++++- server/portal_server.js | 19 ++++++++++++++----- server/storage.js | 22 +++++++++++++++++++++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/frontend/src/fileReceiver.js b/frontend/src/fileReceiver.js index d7fb6a7a..68b651a3 100644 --- a/frontend/src/fileReceiver.js +++ b/frontend/src/fileReceiver.js @@ -1,5 +1,5 @@ const EventEmitter = require('events'); -const { strToIv } = require('./utils'); +const { strToIv, strToUintArr } = require('./utils'); const Raven = window.Raven; @@ -36,6 +36,7 @@ class FileReceiver extends EventEmitter { fileReader.onload = function() { resolve({ data: this.result, + aad: xhr.getResponseHeader('Additional-Data'), fname: xhr .getResponseHeader('Content-Disposition') .match(/=(.+)/)[1] @@ -65,12 +66,15 @@ class FileReceiver extends EventEmitter { ) ]).then(([fdata, key]) => { const salt = this.salt; + console.log(strToUintArr(fdata.aad)); + return Promise.all([ window.crypto.subtle.decrypt( { name: 'AES-GCM', iv: salt, - tagLength: 128 + tagLength: 128, + additionalData: strToUintArr(fdata.aad) }, key, fdata.data diff --git a/frontend/src/fileSender.js b/frontend/src/fileSender.js index ee64ddea..e8f0402e 100644 --- a/frontend/src/fileSender.js +++ b/frontend/src/fileSender.js @@ -8,6 +8,7 @@ class FileSender extends EventEmitter { super(); this.file = file; this.iv = window.crypto.getRandomValues(new Uint8Array(12)); + this.aad = window.crypto.getRandomValues(new Uint8Array(6)); } static delete(fileId, token) { @@ -60,7 +61,8 @@ class FileSender extends EventEmitter { { name: 'AES-GCM', iv: this.iv, - tagLength: 128 + tagLength: 128, + additionalData: this.aad }, secretKey, plaintext @@ -77,6 +79,7 @@ class FileSender extends EventEmitter { const fd = new FormData(); fd.append('fname', file.name); fd.append('data', blob, file.name); + fd.append('aad', this.aad); const xhr = new XMLHttpRequest(); diff --git a/frontend/src/utils.js b/frontend/src/utils.js index f46b4f79..9f8f6f9b 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -20,6 +20,7 @@ function strToIv(str) { return iv; } + function notify(str) { if (!('Notification' in window)) { return; @@ -32,8 +33,13 @@ function notify(str) { } } +function strToUintArr(str) { + return new Uint8Array(str.split(",").map(x => parseInt(x))); +} + module.exports = { ivToStr, strToIv, - notify + notify, + strToUintArr }; diff --git a/server/portal_server.js b/server/portal_server.js index 75317117..c966e882 100644 --- a/server/portal_server.js +++ b/server/portal_server.js @@ -78,14 +78,17 @@ app.get('/assets/download/:id', (req, res) => { return; } - storage - .filename(id) - .then(reply => { + Promise.all([ + storage.filename(id), + storage.aad(id)]) + .then(([reply, aad]) => { storage.length(id).then(contentLength => { + res.writeHead(200, { 'Content-Disposition': 'attachment; filename=' + reply, 'Content-Type': 'application/octet-stream', - 'Content-Length': contentLength + 'Content-Length': contentLength, + 'Additional-Data': aad }); const file_stream = storage.get(id); @@ -142,16 +145,22 @@ app.post('/upload/:id', (req, res, next) => { } req.pipe(req.busboy); + + req.busboy.on('field', (fieldname, value) => { + storage.setField(req.params.id, fieldname, value); + }) + req.busboy.on('file', (fieldname, file, filename) => { log.info('Uploading:', req.params.id); const protocol = conf.env === 'production' ? 'https' : req.protocol; const url = `${protocol}://${req.get('host')}/download/${req.params.id}/`; - storage.set(req.params.id, file, filename, url).then(linkAndID => { res.json(linkAndID); }); }); + + }); app.get('/__lbheartbeat__', (req, res) => { diff --git a/server/storage.js b/server/storage.js index dedf0040..f90d4f07 100644 --- a/server/storage.js +++ b/server/storage.js @@ -27,6 +27,8 @@ if (conf.s3_bucket) { length: awsLength, get: awsGet, set: awsSet, + aad: aad, + setField: setField, delete: awsDelete, forceDelete: awsForceDelete, ping: awsPing @@ -38,6 +40,8 @@ if (conf.s3_bucket) { length: localLength, get: localGet, set: localSet, + aad: aad, + setField: setField, delete: localDelete, forceDelete: localForceDelete, ping: localPing @@ -68,6 +72,22 @@ function exists(id) { }); } +function setField(id, key, value) { + redis_client.hset(id, key, value); +} + +function aad(id) { + return new Promise((resolve, reject) => { + redis_client.hget(id, 'aad', (err, reply) => { + if (!err) { + resolve(reply); + } else { + reject(); + } + }) + }) +} + function localLength(id) { return new Promise((resolve, reject) => { try { @@ -86,7 +106,7 @@ function localSet(id, file, filename, url) { return new Promise((resolve, reject) => { const fstream = fs.createWriteStream(path.join(__dirname, '../static', id)); file.pipe(fstream); - fstream.on('close', () => { + fstream.on('close', () => { const uuid = crypto.randomBytes(10).toString('hex'); redis_client.hmset([id, 'filename', filename, 'delete', uuid]);