From 7d0a34fcebe4174a4cebf3f198ffcf0bed8b8682 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 27 Apr 2017 12:00:32 -0400 Subject: [PATCH] protect mac comparisons from timing attacks --- src/app/services/cryptoService.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/app/services/cryptoService.js b/src/app/services/cryptoService.js index 2dfc017859..dbcb975eb3 100644 --- a/src/app/services/cryptoService.js +++ b/src/app/services/cryptoService.js @@ -358,7 +358,7 @@ angular if (key.macKey && encPieces.length > 2) { var macBytes = forge.util.decode64(encPieces[2]); var computedMacBytes = computeMac(ctBytes, ivBytes, key.macKey, false); - if (!bytesAreEqual(macBytes, computedMacBytes)) { + if (!macsEqual(key.macKey, macBytes, computedMacBytes)) { console.error('MAC failed.'); return null; } @@ -431,18 +431,20 @@ angular return b64Output ? forge.util.encode64(mac.getBytes()) : mac.getBytes(); } - // Constant time comparison. This removes the early-out optimizations of normal equality checks. - function bytesAreEqual(a, b) { - if (a.length !== b.length) { - return false; - } + // Safely compare two MACs in a way that protects against timing attacks. + // ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ + function macsEqual(macKey, mac1, mac2) { + var hmac = forge.hmac.create(); - var result = 0; - for (var i = 0; i < a.length; i++) { - result |= a[i] ^ b[i]; - } + hmac.start('sha256', macKey); + hmac.update(mac1); + mac1 = hmac.digest().getBytes(); - return result === 0; + hmac.start(null, null); + hmac.update(mac2); + mac2 = hmac.digest().getBytes(); + + return mac1 === mac2; } function SymmetricCryptoKey(keyBytes, b64KeyBytes, encType) {