|  |  | @ -36695,6 +36695,23 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ | 
			
		
	
		
		
			
				
					
					|  |  |  |     var calculateMAC = libsignal.crypto.calculateMAC; |  |  |  |     var calculateMAC = libsignal.crypto.calculateMAC; | 
			
		
	
		
		
			
				
					
					|  |  |  |     var verifyMAC    = libsignal.crypto.verifyMAC; |  |  |  |     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 = window.textsecure || {}; | 
			
		
	
		
		
			
				
					
					|  |  |  |     window.textsecure.crypto = { |  |  |  |     window.textsecure.crypto = { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Decrypts message into a raw string
 |  |  |  |         // 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) { |  |  |  |             if (keys.byteLength != 64) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 throw new Error("Got invalid length attachment keys"); |  |  |  |                 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); |  |  |  |             var mac = encryptedBin.slice(encryptedBin.byteLength - 32, encryptedBin.byteLength); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             return verifyMAC(ivAndCiphertext, mac_key, mac, 32).then(function() { |  |  |  |             return verifyMAC(ivAndCiphertext, mac_key, mac, 32).then(function() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if (theirDigest !== undefined) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                   return verifyDigest(encryptedBin, theirDigest); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             }).then(function() { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return decrypt(aes_key, ciphertext, iv); |  |  |  |                 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); |  |  |  |                     var encryptedBin = new Uint8Array(16 + ciphertext.byteLength + 32); | 
			
		
	
		
		
			
				
					
					|  |  |  |                     encryptedBin.set(ivAndCiphertext); |  |  |  |                     encryptedBin.set(ivAndCiphertext); | 
			
		
	
		
		
			
				
					
					|  |  |  |                     encryptedBin.set(new Uint8Array(mac), 16 + ciphertext.byteLength); |  |  |  |                     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; |  |  |  |         return textsecure.storage.get('blocked', []).indexOf(number) >= 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |     }, |  |  |  |     }, | 
			
		
	
		
		
			
				
					
					|  |  |  |     handleAttachment: function(attachment) { |  |  |  |     handleAttachment: function(attachment) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         var digest = attachment.digest ? attachment.digest.toArrayBuffer() : undefined; | 
			
		
	
		
		
			
				
					
					|  |  |  |         function decryptAttachment(encrypted) { |  |  |  |         function decryptAttachment(encrypted) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             return textsecure.crypto.decryptAttachment( |  |  |  |             return textsecure.crypto.decryptAttachment( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 encrypted, |  |  |  |                 encrypted, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 attachment.key.toArrayBuffer() |  |  |  |                 attachment.key.toArrayBuffer(), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 digest | 
			
		
	
		
		
			
				
					
					|  |  |  |             ); |  |  |  |             ); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -39041,10 +39066,11 @@ MessageSender.prototype = { | 
			
		
	
		
		
			
				
					
					|  |  |  |         proto.key = libsignal.crypto.getRandomBytes(64); |  |  |  |         proto.key = libsignal.crypto.getRandomBytes(64); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         var iv = libsignal.crypto.getRandomBytes(16); |  |  |  |         var iv = libsignal.crypto.getRandomBytes(16); | 
			
		
	
		
		
			
				
					
					|  |  |  |         return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(encryptedBin) { |  |  |  |         return textsecure.crypto.encryptAttachment(attachment.data, proto.key, iv).then(function(result) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             return this.server.putAttachment(encryptedBin).then(function(id) { |  |  |  |             return this.server.putAttachment(result.ciphertext).then(function(id) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 proto.id = id; |  |  |  |                 proto.id = id; | 
			
		
	
		
		
			
				
					
					|  |  |  |                 proto.contentType = attachment.contentType; |  |  |  |                 proto.contentType = attachment.contentType; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 proto.digest = result.digest; | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return proto; |  |  |  |                 return proto; | 
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |         }.bind(this)); |  |  |  |         }.bind(this)); | 
			
		
	
	
		
		
			
				
					|  |  | 
 |