protect mac comparisons from timing attacks

This commit is contained in:
Kyle Spearrin 2017-04-27 12:00:32 -04:00
parent b3e94b13f7
commit 7d0a34fceb
1 changed files with 13 additions and 11 deletions

View File

@ -358,7 +358,7 @@ angular
if (key.macKey && encPieces.length > 2) { if (key.macKey && encPieces.length > 2) {
var macBytes = forge.util.decode64(encPieces[2]); var macBytes = forge.util.decode64(encPieces[2]);
var computedMacBytes = computeMac(ctBytes, ivBytes, key.macKey, false); var computedMacBytes = computeMac(ctBytes, ivBytes, key.macKey, false);
if (!bytesAreEqual(macBytes, computedMacBytes)) { if (!macsEqual(key.macKey, macBytes, computedMacBytes)) {
console.error('MAC failed.'); console.error('MAC failed.');
return null; return null;
} }
@ -431,18 +431,20 @@ angular
return b64Output ? forge.util.encode64(mac.getBytes()) : mac.getBytes(); return b64Output ? forge.util.encode64(mac.getBytes()) : mac.getBytes();
} }
// Constant time comparison. This removes the early-out optimizations of normal equality checks. // Safely compare two MACs in a way that protects against timing attacks.
function bytesAreEqual(a, b) { // ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
if (a.length !== b.length) { function macsEqual(macKey, mac1, mac2) {
return false; var hmac = forge.hmac.create();
}
var result = 0; hmac.start('sha256', macKey);
for (var i = 0; i < a.length; i++) { hmac.update(mac1);
result |= a[i] ^ b[i]; 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) { function SymmetricCryptoKey(keyBytes, b64KeyBytes, encType) {