diff --git a/frontend/src/fileReceiver.js b/frontend/src/fileReceiver.js
index d73fae3c..37924038 100644
--- a/frontend/src/fileReceiver.js
+++ b/frontend/src/fileReceiver.js
@@ -1,12 +1,9 @@
 const EventEmitter = require('events');
-const { strToIv } = require('./utils');
-
-const Raven = window.Raven;
+const { hexToArray } = require('./utils');
 
 class FileReceiver extends EventEmitter {
   constructor() {
     super();
-    this.salt = strToIv(location.pathname.slice(10, -1));
   }
 
   download() {
@@ -34,11 +31,12 @@ class FileReceiver extends EventEmitter {
           const blob = new Blob([this.response]);
           const fileReader = new FileReader();
           fileReader.onload = function() {
+            const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
             resolve({
               data: this.result,
-              fname: xhr
-                .getResponseHeader('Content-Disposition')
-                .match(/=(.+)/)[1]
+              aad: meta.aad,
+              filename: meta.filename,
+              iv: meta.id
             });
           };
 
@@ -54,36 +52,53 @@ class FileReceiver extends EventEmitter {
         {
           kty: 'oct',
           k: location.hash.slice(1),
-          alg: 'A128CBC',
+          alg: 'A128GCM',
           ext: true
         },
         {
-          name: 'AES-CBC'
+          name: 'AES-GCM'
         },
         true,
         ['encrypt', 'decrypt']
       )
-    ])
-      .then(([fdata, key]) => {
-        const salt = this.salt;
+    ]).then(([fdata, key]) => {
+      return Promise.all([
+        window.crypto.subtle.decrypt(
+          {
+            name: 'AES-GCM',
+            iv: hexToArray(fdata.iv),
+            additionalData: hexToArray(fdata.aad)
+          },
+          key,
+          fdata.data
+        ),
+        new Promise((resolve, reject) => {
+          resolve(fdata.filename);
+        }),
+        new Promise((resolve, reject) => {
+          resolve(hexToArray(fdata.aad));
+        })
+      ]);
+    }).then(([decrypted, fname, proposedHash]) => {
+      return window.crypto.subtle.digest('SHA-256', decrypted).then(calculatedHash => {
+        const integrity = new Uint8Array(calculatedHash).toString() === proposedHash.toString();
+        if (!integrity) {
+          return new Promise((resolve, reject) => {
+            console.log('This file has been tampered with.')
+            reject();
+          })
+        }
+        
         return Promise.all([
-          window.crypto.subtle.decrypt(
-            {
-              name: 'AES-CBC',
-              iv: salt
-            },
-            key,
-            fdata.data
-          ),
           new Promise((resolve, reject) => {
-            resolve(fdata.fname);
+            resolve(decrypted);
+          }),
+          new Promise((resolve, reject) => {
+            resolve(fname);
           })
         ]);
       })
-      .catch(err => {
-        Raven.captureException(err);
-        return Promise.reject(err);
-      });
+    })
   }
 }
 
diff --git a/frontend/src/fileSender.js b/frontend/src/fileSender.js
index 546613af..8be5f4ae 100644
--- a/frontend/src/fileSender.js
+++ b/frontend/src/fileSender.js
@@ -1,5 +1,5 @@
 const EventEmitter = require('events');
-const { ivToStr } = require('./utils');
+const { arrayToHex } = require('./utils');
 
 const Raven = window.Raven;
 
@@ -7,7 +7,7 @@ class FileSender extends EventEmitter {
   constructor(file) {
     super();
     this.file = file;
-    this.iv = window.crypto.getRandomValues(new Uint8Array(16));
+    this.iv = window.crypto.getRandomValues(new Uint8Array(12));
   }
 
   static delete(fileId, token) {
@@ -37,46 +37,56 @@ class FileSender extends EventEmitter {
 
   upload() {
     return Promise.all([
-      window.crypto.subtle.generateKey(
-        {
-          name: 'AES-CBC',
-          length: 128
-        },
-        true,
-        ['encrypt', 'decrypt']
-      ),
+      window.crypto.subtle
+        .generateKey(
+          {
+            name: 'AES-GCM',
+            length: 128
+          },
+          true,
+          ['encrypt', 'decrypt']
+        )
+        .catch(err =>
+          console.log('There was an error generating a crypto key')
+        ),
       new Promise((resolve, reject) => {
         const reader = new FileReader();
         reader.readAsArrayBuffer(this.file);
         reader.onload = function(event) {
-          resolve(new Uint8Array(this.result));
+          const plaintext = new Uint8Array(this.result);
+          window.crypto.subtle.digest('SHA-256', plaintext).then(hash => {
+            resolve({plaintext: plaintext, hash: new Uint8Array(hash)});
+          })
         };
         reader.onerror = function(err) {
           reject(err);
         };
       })
     ])
-      .then(([secretKey, plaintext]) => {
+      .then(([secretKey, file]) => {
         return Promise.all([
-          window.crypto.subtle.encrypt(
-            {
-              name: 'AES-CBC',
-              iv: this.iv
-            },
-            secretKey,
-            plaintext
-          ),
-          window.crypto.subtle.exportKey('jwk', secretKey)
+          window.crypto.subtle
+            .encrypt(
+              {
+                name: 'AES-GCM',
+                iv: this.iv,
+                additionalData: file.hash,
+                tagLength: 128
+              },
+              secretKey,
+              file.plaintext
+            ),
+          window.crypto.subtle.exportKey('jwk', secretKey),
+          new Promise((resolve, reject) => { resolve(file.hash) })
         ]);
       })
-      .then(([encrypted, keydata]) => {
+      .then(([encrypted, keydata, hash]) => {
         return new Promise((resolve, reject) => {
           const file = this.file;
-          const fileId = ivToStr(this.iv);
+          const fileId = arrayToHex(this.iv);
           const dataView = new DataView(encrypted);
           const blob = new Blob([dataView], { type: file.type });
           const fd = new FormData();
-          fd.append('fname', file.name);
           fd.append('data', blob, file.name);
 
           const xhr = new XMLHttpRequest();
@@ -94,14 +104,22 @@ class FileSender extends EventEmitter {
               const responseObj = JSON.parse(xhr.responseText);
               resolve({
                 url: responseObj.url,
-                fileId: fileId,
+                fileId: responseObj.id,
                 secretKey: keydata.k,
                 deleteToken: responseObj.uuid
               });
             }
           };
 
-          xhr.open('post', '/upload/' + fileId, true);
+          xhr.open('post', '/upload', true);
+          xhr.setRequestHeader(
+            'X-File-Metadata',
+            JSON.stringify({
+              aad: arrayToHex(hash),
+              id: fileId,
+              filename: file.name
+            })
+          );
           xhr.send(fd);
         });
       })
diff --git a/frontend/src/utils.js b/frontend/src/utils.js
index e17534fa..2e6400ce 100644
--- a/frontend/src/utils.js
+++ b/frontend/src/utils.js
@@ -1,4 +1,4 @@
-function ivToStr(iv) {
+function arrayToHex(iv) {
   let hexStr = '';
   for (const i in iv) {
     if (iv[i] < 16) {
@@ -11,8 +11,8 @@ function ivToStr(iv) {
   return hexStr;
 }
 
-function strToIv(str) {
-  const iv = new Uint8Array(16);
+function hexToArray(str) {
+  const iv = new Uint8Array(str.length / 2);
   for (let i = 0; i < str.length; i += 2) {
     iv[i / 2] = parseInt(str.charAt(i) + str.charAt(i + 1), 16);
   }
@@ -33,7 +33,7 @@ function notify(str) {
 }
 
 module.exports = {
-  ivToStr,
-  strToIv,
+  arrayToHex,
+  hexToArray,
   notify
 };
diff --git a/server/portal_server.js b/server/portal_server.js
index 8684417f..c6ed936d 100644
--- a/server/portal_server.js
+++ b/server/portal_server.js
@@ -8,6 +8,7 @@ const bytes = require('bytes');
 const conf = require('./config.js');
 const storage = require('./storage.js');
 const Raven = require('raven');
+const crypto = require('crypto');
 
 if (conf.sentry_dsn) {
   Raven.config(conf.sentry_dsn).install();
@@ -79,13 +80,14 @@ app.get('/assets/download/:id', (req, res) => {
   }
 
   storage
-    .filename(id)
-    .then(reply => {
+    .metadata(id)
+    .then(meta => {
       storage.length(id).then(contentLength => {
         res.writeHead(200, {
-          'Content-Disposition': 'attachment; filename=' + reply,
+          'Content-Disposition': 'attachment; filename=' + meta.filename,
           'Content-Type': 'application/octet-stream',
-          'Content-Length': contentLength
+          'Content-Length': contentLength,
+          'X-File-Metadata': JSON.stringify(meta)
         });
         const file_stream = storage.get(id);
 
@@ -135,21 +137,24 @@ app.post('/delete/:id', (req, res) => {
     .catch(err => res.sendStatus(404));
 });
 
-app.post('/upload/:id', (req, res, next) => {
-  if (!validateID(req.params.id)) {
-    res.sendStatus(404);
-    return;
-  }
-
+app.post('/upload', (req, res, next) => {
+  const newId = crypto.randomBytes(5).toString('hex');
+  const meta = JSON.parse(req.header('X-File-Metadata'));
+  meta.delete = crypto.randomBytes(10).toString('hex');
+  log.info('meta', meta);
   req.pipe(req.busboy);
+
   req.busboy.on('file', (fieldname, file, filename) => {
-    log.info('Uploading:', req.params.id);
+    log.info('Uploading:', newId);
 
-    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);
+    storage.set(newId, file, filename, meta).then(() => {
+      const protocol = conf.env === 'production' ? 'https' : req.protocol;
+      const url = `${protocol}://${req.get('host')}/download/${newId}/`;
+      res.json({
+        url,
+        delete: meta.delete,
+        id: newId
+      });
     });
   });
 });
@@ -171,5 +176,5 @@ app.listen(conf.listen_port, () => {
 });
 
 const validateID = route_id => {
-  return route_id.match(/^[0-9a-fA-F]{32}$/) !== null;
-};
+  return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
+};
\ No newline at end of file
diff --git a/server/storage.js b/server/storage.js
index dedf0040..38559ba3 100644
--- a/server/storage.js
+++ b/server/storage.js
@@ -4,7 +4,6 @@ const s3 = new AWS.S3();
 const conf = require('./config.js');
 const fs = require('fs');
 const path = require('path');
-const crypto = require('crypto');
 
 const mozlog = require('./log.js');
 
@@ -27,9 +26,12 @@ if (conf.s3_bucket) {
     length: awsLength,
     get: awsGet,
     set: awsSet,
+    aad: aad,
+    setField: setField,
     delete: awsDelete,
     forceDelete: awsForceDelete,
-    ping: awsPing
+    ping: awsPing,
+    metadata
   };
 } else {
   module.exports = {
@@ -38,12 +40,27 @@ if (conf.s3_bucket) {
     length: localLength,
     get: localGet,
     set: localSet,
+    aad: aad,
+    setField: setField,
     delete: localDelete,
     forceDelete: localForceDelete,
-    ping: localPing
+    ping: localPing,
+    metadata
   };
 }
 
+function metadata(id) {
+  return new Promise((resolve, reject) => {
+    redis_client.hgetall(id, (err, reply) => {
+      if (!err) {
+        resolve(reply);
+      } else {
+        reject(err);
+      }
+    });
+  });
+}
+
 function filename(id) {
   return new Promise((resolve, reject) => {
     redis_client.hget(id, 'filename', (err, reply) => {
@@ -68,6 +85,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 {
@@ -82,24 +115,19 @@ function localGet(id) {
   return fs.createReadStream(path.join(__dirname, '../static', id));
 }
 
-function localSet(id, file, filename, url) {
+function localSet(newId, file, filename, meta) {
   return new Promise((resolve, reject) => {
-    const fstream = fs.createWriteStream(path.join(__dirname, '../static', id));
+    const fstream = fs.createWriteStream(path.join(__dirname, '../static', newId));
     file.pipe(fstream);
     fstream.on('close', () => {
-      const uuid = crypto.randomBytes(10).toString('hex');
-
-      redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
-      redis_client.expire(id, 86400000);
-      log.info('localSet:', 'Upload Finished of ' + id);
-      resolve({
-        uuid: uuid,
-        url: url
-      });
+      redis_client.hmset(newId, meta);
+      redis_client.expire(newId, 86400000);
+      log.info('localSet:', 'Upload Finished of ' + newId);
+      resolve(meta.delete);
     });
 
     fstream.on('error', () => {
-      log.error('localSet:', 'Failed upload of ' + id);
+      log.error('localSet:', 'Failed upload of ' + newId);
       reject();
     });
   });
@@ -163,10 +191,10 @@ function awsGet(id) {
   }
 }
 
-function awsSet(id, file, filename, url) {
+function awsSet(newId, file, filename, meta) {
   const params = {
     Bucket: conf.s3_bucket,
-    Key: id,
+    Key: newId,
     Body: file
   };
 
@@ -176,16 +204,11 @@ function awsSet(id, file, filename, url) {
         log.info('awsUploadError:', err.stack); // an error occurred
         reject();
       } else {
-        const uuid = crypto.randomBytes(10).toString('hex');
+        redis_client.hmset(newId, meta);
 
-        redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
-
-        redis_client.expire(id, 86400000);
+        redis_client.expire(newId, 86400000);
         log.info('awsUploadFinish', 'Upload Finished of ' + filename);
-        resolve({
-          uuid: uuid,
-          url: url
-        });
+        resolve(meta.delete);
       }
     });
   });
diff --git a/test/aws.storage.test.js b/test/aws.storage.test.js
index 8dbb468a..eef1f2a7 100644
--- a/test/aws.storage.test.js
+++ b/test/aws.storage.test.js
@@ -112,11 +112,8 @@ describe('Testing Set using aws', function() {
     sinon.stub(crypto, 'randomBytes').returns(buf);
     s3Stub.upload.callsArgWith(1, null, {});
     return storage
-      .set('123', {}, 'Filename.moz', 'url.com')
-      .then(reply => {
-        assert.equal(reply.uuid, buf.toString('hex'));
-        assert.equal(reply.url, 'url.com');
-        assert.notEqual(reply.uuid, null);
+      .set('123', {}, 'Filename.moz', {})
+      .then(() => {
         assert(expire.calledOnce);
         assert(expire.calledWith('123', 86400000));
       })
diff --git a/test/local.storage.test.js b/test/local.storage.test.js
index 659710a6..3a9993b2 100644
--- a/test/local.storage.test.js
+++ b/test/local.storage.test.js
@@ -122,10 +122,9 @@ describe('Testing Set to local filesystem', function() {
     fsStub.createWriteStream.returns({ on: stub });
 
     return storage
-      .set('test', { pipe: sinon.stub() }, 'Filename.moz', 'moz.la')
-      .then(reply => {
-        assert(reply.uuid);
-        assert.equal(reply.url, 'moz.la');
+      .set('test', { pipe: sinon.stub() }, 'Filename.moz', {})
+      .then(() => {
+        assert(1);
       })
       .catch(err => assert.fail());
   });