|
@@ -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));
|