From ac7c95fed0eb1c2097a46d8cc544d4e2a6f2f645 Mon Sep 17 00:00:00 2001 From: lilia Date: Tue, 27 Oct 2015 12:15:08 -0700 Subject: [PATCH] Validate argument lengths in crypto.js These functions accept an array buffer and extract an AES and MAC key from it without verifying it has the appropriate length. Ciphertext messages are similarly dissected. The slice function does not raise an error on out of bounds accesses but instead returns an empty or partially-filled array. Empty or short arrays will be passed through to the window.crypto.subtle API, where they will raise an error. We should not rely on the Web Crypto API to validate key lengths or for MAC checks to fail. Instead, validate the lengths of given parameters before extracting their components. // FREEBIE --- js/libtextsecure.js | 29 +++++++++++++++++++++++++---- libtextsecure/crypto.js | 29 +++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 24ddcc85f..7e8034e63 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -37897,12 +37897,20 @@ axolotlInternal.RecipientRecord = function() { window.textsecure.crypto = { // Decrypts message into a raw string decryptWebsocketMessage: function(message, signaling_key) { - var aes_key = signaling_key.slice(0, 32); - var mac_key = signaling_key.slice(32, 32 + 20); - var decodedMessage = message.toArrayBuffer(); - if (new Uint8Array(decodedMessage)[0] != 1) + + if (signaling_key.byteLength != 52) { + throw new Error("Got invalid length signaling_key"); + } + if (decodedMessage.byteLength < 1 + 16 + 10) { + throw new Error("Got invalid length message"); + } + if (new Uint8Array(decodedMessage)[0] != 1) { throw new Error("Got bad version number: " + decodedMessage[0]); + } + + var aes_key = signaling_key.slice(0, 32); + var mac_key = signaling_key.slice(32, 32 + 20); var iv = decodedMessage.slice(1, 1 + 16); var ciphertext = decodedMessage.slice(1 + 16, decodedMessage.byteLength - 10); @@ -37915,6 +37923,13 @@ axolotlInternal.RecipientRecord = function() { }, decryptAttachment: function(encryptedBin, keys) { + if (keys.byteLength != 64) { + throw new Error("Got invalid length attachment keys"); + } + if (encryptedBin.byteLength < 16 + 32) { + throw new Error("Got invalid length attachment"); + } + var aes_key = keys.slice(0, 32); var mac_key = keys.slice(32, 64); @@ -37929,6 +37944,12 @@ axolotlInternal.RecipientRecord = function() { }, encryptAttachment: function(plaintext, keys, iv) { + if (keys.byteLength != 64) { + throw new Error("Got invalid length attachment keys"); + } + if (iv.byteLength != 16) { + throw new Error("Got invalid length attachment iv"); + } var aes_key = keys.slice(0, 32); var mac_key = keys.slice(32, 64); diff --git a/libtextsecure/crypto.js b/libtextsecure/crypto.js index 185b38e03..df1d6b77f 100644 --- a/libtextsecure/crypto.js +++ b/libtextsecure/crypto.js @@ -36,12 +36,20 @@ window.textsecure.crypto = { // Decrypts message into a raw string decryptWebsocketMessage: function(message, signaling_key) { - var aes_key = signaling_key.slice(0, 32); - var mac_key = signaling_key.slice(32, 32 + 20); - var decodedMessage = message.toArrayBuffer(); - if (new Uint8Array(decodedMessage)[0] != 1) + + if (signaling_key.byteLength != 52) { + throw new Error("Got invalid length signaling_key"); + } + if (decodedMessage.byteLength < 1 + 16 + 10) { + throw new Error("Got invalid length message"); + } + if (new Uint8Array(decodedMessage)[0] != 1) { throw new Error("Got bad version number: " + decodedMessage[0]); + } + + var aes_key = signaling_key.slice(0, 32); + var mac_key = signaling_key.slice(32, 32 + 20); var iv = decodedMessage.slice(1, 1 + 16); var ciphertext = decodedMessage.slice(1 + 16, decodedMessage.byteLength - 10); @@ -54,6 +62,13 @@ }, decryptAttachment: function(encryptedBin, keys) { + if (keys.byteLength != 64) { + throw new Error("Got invalid length attachment keys"); + } + if (encryptedBin.byteLength < 16 + 32) { + throw new Error("Got invalid length attachment"); + } + var aes_key = keys.slice(0, 32); var mac_key = keys.slice(32, 64); @@ -68,6 +83,12 @@ }, encryptAttachment: function(plaintext, keys, iv) { + if (keys.byteLength != 64) { + throw new Error("Got invalid length attachment keys"); + } + if (iv.byteLength != 16) { + throw new Error("Got invalid length attachment iv"); + } var aes_key = keys.slice(0, 32); var mac_key = keys.slice(32, 64);