From 43de0cc2ec433f6fae7c26e01d7ae9e06ed855d7 Mon Sep 17 00:00:00 2001 From: lilia Date: Tue, 7 Mar 2017 16:54:15 -0800 Subject: [PATCH] Add attachment digests // FREEBIE --- js/libtextsecure.js | 36 ++++++++++++++++++++++---- libtextsecure/crypto.js | 27 +++++++++++++++++-- libtextsecure/message_receiver.js | 4 ++- libtextsecure/sendmessage.js | 5 ++-- protos/IncomingPushMessageSignal.proto | 3 +++ 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 8c33acbd5fc..3f3e184f5f6 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -36695,6 +36695,23 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ var calculateMAC = libsignal.crypto.calculateMAC; var verifyMAC = libsignal.crypto.verifyMAC; + function verifyDigest(data, theirDigest) { + return crypto.subtle.digest({name: 'SHA-256'}, data).then(function(ourDigest) { + var a = new Uint8Array(ourDigest); + var b = new Uint8Array(theirDigest); + var result = 0; + for (var i=0; i < theirDigest.byteLength; ++i) { + result = result | (a[i] ^ b[i]); + } + if (result !== 0) { + throw new Error('Bad digest'); + } + }); + } + function calculateDigest(data) { + return crypto.subtle.digest({name: 'SHA-256'}, data); + } + window.textsecure = window.textsecure || {}; window.textsecure.crypto = { // Decrypts message into a raw string @@ -36724,7 +36741,7 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ }); }, - decryptAttachment: function(encryptedBin, keys) { + decryptAttachment: function(encryptedBin, keys, theirDigest) { if (keys.byteLength != 64) { throw new Error("Got invalid length attachment keys"); } @@ -36741,6 +36758,10 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ var mac = encryptedBin.slice(encryptedBin.byteLength - 32, encryptedBin.byteLength); return verifyMAC(ivAndCiphertext, mac_key, mac, 32).then(function() { + if (theirDigest !== undefined) { + return verifyDigest(encryptedBin, theirDigest); + } + }).then(function() { return decrypt(aes_key, ciphertext, iv); }); }, @@ -36764,7 +36785,9 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ var encryptedBin = new Uint8Array(16 + ciphertext.byteLength + 32); encryptedBin.set(ivAndCiphertext); encryptedBin.set(new Uint8Array(mac), 16 + ciphertext.byteLength); - return encryptedBin.buffer; + return calculateDigest(encryptedBin.buffer).then(function(digest) { + return { ciphertext: encryptedBin.buffer, digest: digest }; + }); }); }); }, @@ -38539,10 +38562,12 @@ MessageReceiver.prototype.extend({ return textsecure.storage.get('blocked', []).indexOf(number) >= 0; }, handleAttachment: function(attachment) { + var digest = attachment.digest ? attachment.digest.toArrayBuffer() : undefined; function decryptAttachment(encrypted) { return textsecure.crypto.decryptAttachment( encrypted, - attachment.key.toArrayBuffer() + attachment.key.toArrayBuffer(), + digest ); } @@ -39041,10 +39066,11 @@ MessageSender.prototype = { proto.key = libsignal.crypto.getRandomBytes(64); var iv = libsignal.crypto.getRandomBytes(16); - return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(encryptedBin) { - return this.server.putAttachment(encryptedBin).then(function(id) { + return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(result) { + return this.server.putAttachment(result.ciphertext).then(function(id) { proto.id = id; proto.contentType = attachment.contentType; + proto.digest = result.digest; return proto; }); }.bind(this)); diff --git a/libtextsecure/crypto.js b/libtextsecure/crypto.js index b14ba73da2e..792e03fb754 100644 --- a/libtextsecure/crypto.js +++ b/libtextsecure/crypto.js @@ -10,6 +10,23 @@ var calculateMAC = libsignal.crypto.calculateMAC; var verifyMAC = libsignal.crypto.verifyMAC; + function verifyDigest(data, theirDigest) { + return crypto.subtle.digest({name: 'SHA-256'}, data).then(function(ourDigest) { + var a = new Uint8Array(ourDigest); + var b = new Uint8Array(theirDigest); + var result = 0; + for (var i=0; i < theirDigest.byteLength; ++i) { + result = result | (a[i] ^ b[i]); + } + if (result !== 0) { + throw new Error('Bad digest'); + } + }); + } + function calculateDigest(data) { + return crypto.subtle.digest({name: 'SHA-256'}, data); + } + window.textsecure = window.textsecure || {}; window.textsecure.crypto = { // Decrypts message into a raw string @@ -39,7 +56,7 @@ }); }, - decryptAttachment: function(encryptedBin, keys) { + decryptAttachment: function(encryptedBin, keys, theirDigest) { if (keys.byteLength != 64) { throw new Error("Got invalid length attachment keys"); } @@ -56,6 +73,10 @@ var mac = encryptedBin.slice(encryptedBin.byteLength - 32, encryptedBin.byteLength); return verifyMAC(ivAndCiphertext, mac_key, mac, 32).then(function() { + if (theirDigest !== undefined) { + return verifyDigest(encryptedBin, theirDigest); + } + }).then(function() { return decrypt(aes_key, ciphertext, iv); }); }, @@ -79,7 +100,9 @@ var encryptedBin = new Uint8Array(16 + ciphertext.byteLength + 32); encryptedBin.set(ivAndCiphertext); encryptedBin.set(new Uint8Array(mac), 16 + ciphertext.byteLength); - return encryptedBin.buffer; + return calculateDigest(encryptedBin.buffer).then(function(digest) { + return { ciphertext: encryptedBin.buffer, digest: digest }; + }); }); }); }, diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 167c48c71e7..33ec0c59dc6 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -338,10 +338,12 @@ MessageReceiver.prototype.extend({ return textsecure.storage.get('blocked', []).indexOf(number) >= 0; }, handleAttachment: function(attachment) { + var digest = attachment.digest ? attachment.digest.toArrayBuffer() : undefined; function decryptAttachment(encrypted) { return textsecure.crypto.decryptAttachment( encrypted, - attachment.key.toArrayBuffer() + attachment.key.toArrayBuffer(), + digest ); } diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index bc4a483f694..17c38b02e10 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -119,10 +119,11 @@ MessageSender.prototype = { proto.key = libsignal.crypto.getRandomBytes(64); var iv = libsignal.crypto.getRandomBytes(16); - return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(encryptedBin) { - return this.server.putAttachment(encryptedBin).then(function(id) { + return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(result) { + return this.server.putAttachment(result.ciphertext).then(function(id) { proto.id = id; proto.contentType = attachment.contentType; + proto.digest = result.digest; return proto; }); }.bind(this)); diff --git a/protos/IncomingPushMessageSignal.proto b/protos/IncomingPushMessageSignal.proto index 446eb25fbe5..50d3fbb1d31 100644 --- a/protos/IncomingPushMessageSignal.proto +++ b/protos/IncomingPushMessageSignal.proto @@ -120,6 +120,9 @@ message AttachmentPointer { optional fixed64 id = 1; optional string contentType = 2; optional bytes key = 3; + optional uint32 size = 4; + optional bytes thumbnail = 5; + optional bytes digest = 6; } message GroupContext {