diff --git a/libs/common/src/platform/enums/encryption-type.enum.ts b/libs/common/src/platform/enums/encryption-type.enum.ts index b4ecd78049..a0ffe67927 100644 --- a/libs/common/src/platform/enums/encryption-type.enum.ts +++ b/libs/common/src/platform/enums/encryption-type.enum.ts @@ -8,6 +8,14 @@ export enum EncryptionType { 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. * For example, an EncString of type AesCbc256_B64 will have 2 parts, and an EncString of type * AesCbc128_HmacSha256_B64 will have 3 parts. diff --git a/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts b/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts index 681972e7e4..8c42c724b2 100644 --- a/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts +++ b/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts @@ -2,7 +2,7 @@ import { Utils } from "../../../platform/misc/utils"; import { CryptoFunctionService } from "../../abstractions/crypto-function.service"; import { EncryptService } from "../../abstractions/encrypt.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 { Encrypted } from "../../interfaces/encrypted"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; @@ -70,13 +70,24 @@ export class EncryptServiceImplementation implements EncryptService { 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) { - 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; } 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; } @@ -94,7 +105,12 @@ export class EncryptServiceImplementation implements EncryptService { ); const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac); 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; } } @@ -113,13 +129,24 @@ export class EncryptServiceImplementation implements EncryptService { 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) { - 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; } 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; } @@ -129,13 +156,25 @@ export class EncryptServiceImplementation implements EncryptService { macData.set(new Uint8Array(encThing.dataBytes), encThing.ivBytes.byteLength); const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256"); 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; } const macsMatch = await this.cryptoFunctionService.compare(encThing.macBytes, computedMac); 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; } } @@ -164,7 +203,7 @@ export class EncryptServiceImplementation implements EncryptService { async rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise { 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"; @@ -182,7 +221,7 @@ export class EncryptServiceImplementation implements EncryptService { } 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);