1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-19 02:51:14 +02:00

hmac check on rsa decrypt

This commit is contained in:
Kyle Spearrin 2017-06-19 11:09:48 -04:00
parent 4b9712d034
commit 8ff336d103
2 changed files with 65 additions and 28 deletions

View File

@ -10,7 +10,9 @@ function ConstantsService() {
AesCbc128_HmacSha256_B64: 1, AesCbc128_HmacSha256_B64: 1,
AesCbc256_HmacSha256_B64: 2, AesCbc256_HmacSha256_B64: 2,
Rsa2048_OaepSha256_B64: 3, Rsa2048_OaepSha256_B64: 3,
Rsa2048_OaepSha1_B64: 4 Rsa2048_OaepSha1_B64: 4,
Rsa2048_OaepSha256_HmacSha256_B64: 5,
Rsa2048_OaepSha1_HmacSha256_B64: 6
} }
}; };
}; };

View File

@ -427,7 +427,7 @@ function initCryptoService(constantsService) {
var iv = forge.util.encode64(ivBytes); var iv = forge.util.encode64(ivBytes);
var ctBytes = cipher.output.getBytes(); var ctBytes = cipher.output.getBytes();
var ct = forge.util.encode64(ctBytes); var ct = forge.util.encode64(ctBytes);
var mac = !key.macKey ? null : computeMac(ctBytes, ivBytes, key.macKey, true); var mac = !key.macKey ? null : computeMac(ivBytes + ctBytes, key.macKey, true);
var cs = new CipherString(key.encType, iv, ct, mac); var cs = new CipherString(key.encType, iv, ct, mac);
deferred.resolve(cs); deferred.resolve(cs);
@ -473,7 +473,7 @@ function initCryptoService(constantsService) {
if (key.macKey && cipherString.mac) { if (key.macKey && cipherString.mac) {
var macBytes = forge.util.decode64(cipherString.mac); var macBytes = forge.util.decode64(cipherString.mac);
var computedMacBytes = computeMac(ctBytes, ivBytes, key.macKey, false); var computedMacBytes = computeMac(ivBytes + ctBytes, key.macKey, false);
if (!macsEqual(key.macKey, computedMacBytes, macBytes)) { if (!macsEqual(key.macKey, computedMacBytes, macBytes)) {
console.error('MAC failed.'); console.error('MAC failed.');
deferred.reject('MAC failed.'); deferred.reject('MAC failed.');
@ -503,38 +503,64 @@ function initCryptoService(constantsService) {
CryptoService.prototype.rsaDecrypt = function (encValue) { CryptoService.prototype.rsaDecrypt = function (encValue) {
var headerPieces = encValue.split('.'), var headerPieces = encValue.split('.'),
encType, encType,
encPiece; encPieces;
if (headerPieces.length === 1) { if (headerPieces.length === 1) {
encType = constantsService.encType.Rsa2048_OaepSha256_B64; encType = constantsService.encType.Rsa2048_OaepSha256_B64;
encPiece = headerPieces[0]; encPieces = [headerPieces[0]];
} }
else if (headerPieces.length === 2) { else if (headerPieces.length === 2) {
try { try {
encType = parseInt(headerPieces[0]); encType = parseInt(headerPieces[0]);
encPiece = headerPieces[1]; encPieces = headerPieces[1].split('|');
} }
catch (e) { } catch (e) { }
} }
var padding = null; switch (encType) {
if (encType === constantsService.encType.Rsa2048_OaepSha256_B64) { case constantsService.encType.Rsa2048_OaepSha256_B64:
padding = { case constantsService.encType.Rsa2048_OaepSha1_B64:
name: 'RSA-OAEP', if (encPieces.length !== 1) {
hash: { name: 'SHA-256' } throw 'Invalid cipher format.';
} }
} break;
else if (encType === constantsService.encType.Rsa2048_OaepSha1_B64) { case constantsService.encType.Rsa2048_OaepSha256_HmacSha256_B64:
padding = { case constantsService.encType.Rsa2048_OaepSha1_HmacSha256_B64:
name: 'RSA-OAEP', if (encPieces.length !== 2) {
hash: { name: 'SHA-1' } throw 'Invalid cipher format.';
} }
} break;
else { default:
throw 'encType unavailable.'; throw 'encType unavailable.';
} }
return this.getPrivateKey().then(function (privateKeyBytes) { var padding = null;
switch (encType) {
case constantsService.encType.Rsa2048_OaepSha256_B64:
case constantsService.encType.Rsa2048_OaepSha256_HmacSha256_B64:
padding = {
name: 'RSA-OAEP',
hash: { name: 'SHA-256' }
}
break;
case constantsService.encType.Rsa2048_OaepSha1_B64:
case constantsService.encType.Rsa2048_OaepSha1_HmacSha256_B64:
padding = {
name: 'RSA-OAEP',
hash: { name: 'SHA-1' }
}
break;
default:
throw 'encType unavailable.';
}
var key = null,
self = this;
return self.getEncKey().then(function (encKey) {
key = encKey;
return self.getPrivateKey();
}).then(function (privateKeyBytes) {
if (!privateKeyBytes) { if (!privateKeyBytes) {
throw 'No private key.'; throw 'No private key.';
} }
@ -545,12 +571,21 @@ function initCryptoService(constantsService) {
return window.crypto.subtle.importKey('pkcs8', privateKeyBytes, padding, false, ['decrypt']); return window.crypto.subtle.importKey('pkcs8', privateKeyBytes, padding, false, ['decrypt']);
}).then(function (privateKey) { }).then(function (privateKey) {
if (!encPiece) { if (!encPieces || !encPieces.length) {
throw 'encPiece unavailable.'; throw 'encPieces unavailable.';
} }
var ctBytes = fromB64ToBuffer(encPiece); if (key && key.macKey && encPieces.length > 1) {
return window.crypto.subtle.decrypt({ name: padding.name }, privateKey, ctBytes); var ctBytes = forge.util.decode64(encPieces[0]);
var macBytes = forge.util.decode64(encPieces[1]);
var computedMacBytes = computeMac(ctBytes, key.macKey, false);
if (!macsEqual(key.macKey, macBytes, computedMacBytes)) {
throw 'MAC failed.';
}
}
var ctBuff = fromB64ToBuffer(encPieces[0]);
return window.crypto.subtle.decrypt({ name: padding.name }, privateKey, ctBuff);
}, function () { }, function () {
throw 'Cannot import privateKey.'; throw 'Cannot import privateKey.';
}).then(function (decBytes) { }).then(function (decBytes) {
@ -561,10 +596,10 @@ function initCryptoService(constantsService) {
}); });
}; };
function computeMac(ct, iv, macKey, b64Output) { function computeMac(dataBytes, macKey, b64Output) {
var hmac = forge.hmac.create(); var hmac = forge.hmac.create();
hmac.start('sha256', macKey); hmac.start('sha256', macKey);
hmac.update(iv + ct); hmac.update(dataBytes);
var mac = hmac.digest(); var mac = hmac.digest();
return b64Output ? forge.util.encode64(mac.getBytes()) : mac.getBytes(); return b64Output ? forge.util.encode64(mac.getBytes()) : mac.getBytes();
} }