use random bytes for each HMAC comparison

This commit is contained in:
Kyle Spearrin 2018-01-18 12:07:32 -05:00
parent df2e332134
commit 179765f6e4
1 changed files with 21 additions and 7 deletions

View File

@ -540,7 +540,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(ivBytes + ctBytes, key.macKey, false); var computedMacBytes = computeMac(ivBytes + ctBytes, key.macKey, false);
if (!macsEqual(key.macKey, macBytes, computedMacBytes)) { if (!macsEqual(macBytes, computedMacBytes)) {
console.error('MAC failed.'); console.error('MAC failed.');
return null; return null;
} }
@ -650,7 +650,7 @@ angular
if (computedMacBuf === null) { if (computedMacBuf === null) {
return null; return null;
} }
return macsEqualWC(keyBuf.macKey, macBuf, computedMacBuf); return macsEqualWC(macBuf, computedMacBuf);
}).then(function (macsMatch) { }).then(function (macsMatch) {
if (macsMatch === false) { if (macsMatch === false) {
console.error('MAC failed.'); console.error('MAC failed.');
@ -708,7 +708,7 @@ angular
if (key && key.macKey && encPieces.length > 1) { if (key && key.macKey && encPieces.length > 1) {
var macBytes = forge.util.decode64(encPieces[1]); var macBytes = forge.util.decode64(encPieces[1]);
var computedMacBytes = computeMac(ctBytes, key.macKey, false); var computedMacBytes = computeMac(ctBytes, key.macKey, false);
if (!macsEqual(key.macKey, macBytes, computedMacBytes)) { if (!macsEqual(macBytes, computedMacBytes)) {
console.error('MAC failed.'); console.error('MAC failed.');
return null; return null;
} }
@ -751,10 +751,11 @@ angular
// Safely compare two MACs in a way that protects against timing attacks (Double HMAC Verification). // Safely compare two MACs in a way that protects against timing attacks (Double HMAC Verification).
// ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ // ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
function macsEqual(macKey, mac1, mac2) { // ref: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
function macsEqual(mac1, mac2) {
var hmac = forge.hmac.create(); var hmac = forge.hmac.create();
hmac.start('sha256', macKey); hmac.start('sha256', getRandomBytes(32));
hmac.update(mac1); hmac.update(mac1);
mac1 = hmac.digest().getBytes(); mac1 = hmac.digest().getBytes();
@ -765,11 +766,14 @@ angular
return mac1 === mac2; return mac1 === mac2;
} }
function macsEqualWC(macKeyBuf, mac1Buf, mac2Buf) { function macsEqualWC(mac1Buf, mac2Buf) {
var mac1, var mac1,
macKey; macKey;
return window.crypto.subtle.importKey('raw', macKeyBuf, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']) var compareKey = new Uint8Array(32);
_crypto.getRandomValues(compareKey);
return window.crypto.subtle.importKey('raw', compareKey.buffer, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'])
.then(function (key) { .then(function (key) {
macKey = key; macKey = key;
return window.crypto.subtle.sign({ name: 'HMAC', hash: { name: 'SHA-256' } }, macKey, mac1Buf); return window.crypto.subtle.sign({ name: 'HMAC', hash: { name: 'SHA-256' } }, macKey, mac1Buf);
@ -936,5 +940,15 @@ angular
return new Uint8Array(result); return new Uint8Array(result);
} }
function getRandomBytes(byteLength) {
var bytes = new Uint32Array(byteLength / 4);
_crypto.getRandomValues(bytes);
var buffer = forge.util.createBuffer();
for (var i = 0; i < bytes.length; i++) {
buffer.putInt32(bytes[i]);
}
return buffer.getBytes();
}
return _service; return _service;
}); });