1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-21 16:18:28 +01:00

Add logging for decryption failures (#11683)

* Add logging to decryption routines

* Fix case of uknown encryption type

* Remove enum to string mapping
This commit is contained in:
Bernd Schoolmann 2024-10-24 15:43:49 +02:00 committed by GitHub
parent 9b471e6633
commit b3b311e164
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 10 deletions

View File

@ -8,6 +8,14 @@ export enum EncryptionType {
Rsa2048_OaepSha1_HmacSha256_B64 = 6, Rsa2048_OaepSha1_HmacSha256_B64 = 6,
} }
export function encryptionTypeToString(encryptionType: EncryptionType): string {
if (encryptionType in EncryptionType) {
return EncryptionType[encryptionType];
} else {
return "Unknown encryption type " + encryptionType;
}
}
/** The expected number of parts to a serialized EncString of the given encryption type. /** The expected number of parts to a serialized EncString of the given encryption type.
* For example, an EncString of type AesCbc256_B64 will have 2 parts, and an EncString of type * For example, an EncString of type AesCbc256_B64 will have 2 parts, and an EncString of type
* AesCbc128_HmacSha256_B64 will have 3 parts. * AesCbc128_HmacSha256_B64 will have 3 parts.

View File

@ -2,7 +2,7 @@ import { Utils } from "../../../platform/misc/utils";
import { CryptoFunctionService } from "../../abstractions/crypto-function.service"; import { CryptoFunctionService } from "../../abstractions/crypto-function.service";
import { EncryptService } from "../../abstractions/encrypt.service"; import { EncryptService } from "../../abstractions/encrypt.service";
import { LogService } from "../../abstractions/log.service"; import { LogService } from "../../abstractions/log.service";
import { EncryptionType } from "../../enums"; import { EncryptionType, encryptionTypeToString as encryptionTypeName } from "../../enums";
import { Decryptable } from "../../interfaces/decryptable.interface"; import { Decryptable } from "../../interfaces/decryptable.interface";
import { Encrypted } from "../../interfaces/encrypted"; import { Encrypted } from "../../interfaces/encrypted";
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
@ -70,13 +70,24 @@ export class EncryptServiceImplementation implements EncryptService {
key = this.resolveLegacyKey(key, encString); key = this.resolveLegacyKey(key, encString);
// DO NOT REMOVE OR MOVE. This prevents downgrade to mac-less CBC, which would compromise integrity and confidentiality.
if (key.macKey != null && encString?.mac == null) { if (key.macKey != null && encString?.mac == null) {
this.logService.error("MAC required but not provided."); this.logService.error(
"[Encrypt service] Key has mac key but payload is missing mac bytes. Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encString.encryptionType),
);
return null; return null;
} }
if (key.encType !== encString.encryptionType) { if (key.encType !== encString.encryptionType) {
this.logService.error("Key encryption type does not match payload encryption type."); this.logService.error(
"[Encrypt service] Key encryption type does not match payload encryption type. Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encString.encryptionType),
);
return null; return null;
} }
@ -94,7 +105,12 @@ export class EncryptServiceImplementation implements EncryptService {
); );
const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac); const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac);
if (!macsEqual) { if (!macsEqual) {
this.logMacFailed("MAC comparison failed. Key or payload has changed."); this.logMacFailed(
"[Encrypt service] MAC comparison failed. Key or payload has changed. Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encString.encryptionType),
);
return null; return null;
} }
} }
@ -113,13 +129,24 @@ export class EncryptServiceImplementation implements EncryptService {
key = this.resolveLegacyKey(key, encThing); key = this.resolveLegacyKey(key, encThing);
// DO NOT REMOVE OR MOVE. This prevents downgrade to mac-less CBC, which would compromise integrity and confidentiality.
if (key.macKey != null && encThing.macBytes == null) { if (key.macKey != null && encThing.macBytes == null) {
this.logService.error("MAC required but not provided."); this.logService.error(
"[Encrypt service] Key has mac key but payload is missing mac bytes. Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encThing.encryptionType),
);
return null; return null;
} }
if (key.encType !== encThing.encryptionType) { if (key.encType !== encThing.encryptionType) {
this.logService.error("Key encryption type does not match payload encryption type."); this.logService.error(
"[Encrypt service] Key encryption type does not match payload encryption type. Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encThing.encryptionType),
);
return null; return null;
} }
@ -129,13 +156,25 @@ export class EncryptServiceImplementation implements EncryptService {
macData.set(new Uint8Array(encThing.dataBytes), encThing.ivBytes.byteLength); macData.set(new Uint8Array(encThing.dataBytes), encThing.ivBytes.byteLength);
const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256"); const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256");
if (computedMac === null) { if (computedMac === null) {
this.logMacFailed("Failed to compute MAC."); this.logMacFailed(
"[Encrypt service] Failed to compute MAC." +
" Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encThing.encryptionType),
);
return null; return null;
} }
const macsMatch = await this.cryptoFunctionService.compare(encThing.macBytes, computedMac); const macsMatch = await this.cryptoFunctionService.compare(encThing.macBytes, computedMac);
if (!macsMatch) { if (!macsMatch) {
this.logMacFailed("MAC comparison failed. Key or payload has changed."); this.logMacFailed(
"[Encrypt service] MAC comparison failed. Key or payload has changed." +
" Key type " +
encryptionTypeName(key.encType) +
" Payload type " +
encryptionTypeName(encThing.encryptionType),
);
return null; return null;
} }
} }
@ -164,7 +203,7 @@ export class EncryptServiceImplementation implements EncryptService {
async rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array> { async rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array> {
if (data == null) { if (data == null) {
throw new Error("No data provided for decryption."); throw new Error("[Encrypt service] rsaDecrypt: No data provided for decryption.");
} }
let algorithm: "sha1" | "sha256"; let algorithm: "sha1" | "sha256";
@ -182,7 +221,7 @@ export class EncryptServiceImplementation implements EncryptService {
} }
if (privateKey == null) { if (privateKey == null) {
throw new Error("No private key provided for decryption."); throw new Error("[Encrypt service] rsaDecrypt: No private key provided for decryption.");
} }
return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm); return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm);