diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 019be2923b6..4c35dc39a3f 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -92,6 +92,7 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SdkPureClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { @@ -114,10 +115,10 @@ import { ConfigApiService } from "@bitwarden/common/platform/services/config/con import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; -import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-encrypt.service.implementation"; +// import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-encrypt.service.implementation"; import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation"; import { FallbackBulkEncryptService } from "@bitwarden/common/platform/services/cryptography/fallback-bulk-encrypt.service"; -import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; +// import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/services/fido2/fido2-active-request-manager"; import { Fido2AuthenticatorService } from "@bitwarden/common/platform/services/fido2/fido2-authenticator.service"; import { Fido2ClientService } from "@bitwarden/common/platform/services/fido2/fido2-client.service"; @@ -257,7 +258,10 @@ import { LocalBackedSessionStorageService } from "../platform/services/local-bac import { BackgroundPlatformUtilsService } from "../platform/services/platform-utils/background-platform-utils.service"; import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service"; import { PopupViewCacheBackgroundService } from "../platform/services/popup-view-cache-background.service"; -import { BrowserSdkClientFactory } from "../platform/services/sdk/browser-sdk-client-factory"; +import { + BrowserSdkClientFactory, + BrowserSdkPureClientFactory, +} from "../platform/services/sdk/browser-sdk-client-factory"; import { BackgroundTaskSchedulerService } from "../platform/services/task-scheduler/background-task-scheduler.service"; import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service"; import { BrowserStorageServiceProvider } from "../platform/storage/browser-storage-service.provider"; @@ -377,6 +381,7 @@ export default class MainBackground { themeStateService: DefaultThemeStateService; autoSubmitLoginBackground: AutoSubmitLoginBackground; sdkService: SdkService; + pureSdkClientFactory: SdkPureClientFactory; cipherAuthorizationService: CipherAuthorizationService; inlineMenuFieldQualificationService: InlineMenuFieldQualificationService; @@ -494,13 +499,19 @@ export default class MainBackground { return derivedKey; }); + this.pureSdkClientFactory = new BrowserSdkPureClientFactory(this.logService); this.largeObjectMemoryStorageForStateProviders = new LocalBackedSessionStorageService( sessionKey, this.storageService, // For local backed session storage, we expect that the encrypted data on disk will persist longer than the encryption key in memory // and failures to decrypt because of that are completely expected. For this reason, we pass in `false` to the `EncryptServiceImplementation` // so that MAC failures are not logged. - new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false), + new EncryptServiceImplementation( + this.pureSdkClientFactory, + this.cryptoFunctionService, + this.logService, + false, + ), this.platformUtilsService, this.logService, ); @@ -536,12 +547,18 @@ export default class MainBackground { ); this.encryptService = BrowserApi.isManifestVersion(2) - ? new MultithreadEncryptServiceImplementation( + ? new EncryptServiceImplementation( + this.pureSdkClientFactory, this.cryptoFunctionService, this.logService, true, ) - : new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true); + : new EncryptServiceImplementation( + this.pureSdkClientFactory, + this.cryptoFunctionService, + this.logService, + true, + ); this.singleUserStateProvider = new DefaultSingleUserStateProvider( storageServiceProvider, @@ -1287,14 +1304,14 @@ export default class MainBackground { this.syncServiceListener?.listener$().subscribe(); await this.autoSubmitLoginBackground.init(); - if ( - BrowserApi.isManifestVersion(2) && - (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) - ) { - await this.bulkEncryptService.setFeatureFlagEncryptService( - new BulkEncryptServiceImplementation(this.cryptoFunctionService, this.logService), - ); - } + // if ( + // BrowserApi.isManifestVersion(2) && + // (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) + // ) { + // await this.bulkEncryptService.setFeatureFlagEncryptService( + // new BulkEncryptServiceImplementation(this.cryptoFunctionService, this.logService), + // ); + // } // If the user is logged out, switch to the next account const active = await firstValueFrom(this.accountService.activeAccount$); diff --git a/apps/browser/src/platform/services/sdk/browser-sdk-client-factory.ts b/apps/browser/src/platform/services/sdk/browser-sdk-client-factory.ts index c9d5d726a6a..dc86fda2f6b 100644 --- a/apps/browser/src/platform/services/sdk/browser-sdk-client-factory.ts +++ b/apps/browser/src/platform/services/sdk/browser-sdk-client-factory.ts @@ -1,9 +1,12 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; +import { + SdkClientFactory, + SdkPureClientFactory, +} from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { RecoverableSDKError } from "@bitwarden/common/platform/services/sdk/default-sdk.service"; -import type { BitwardenClient } from "@bitwarden/sdk-internal"; +import type { BitwardenClient, BitwardenPure } from "@bitwarden/sdk-internal"; import { BrowserApi } from "../../browser/browser-api"; @@ -60,6 +63,32 @@ async function load() { } } +export class BrowserSdkPureClientFactory implements SdkPureClientFactory { + constructor(private readonly logService: LogService) {} + async createPureSdkClient(): Promise { + const startTime = performance.now(); + try { + await loadWithTimeout(); + } catch (error) { + throw new Error(`Failed to load: ${error.message}`); + } + + const endTime = performance.now(); + const elapsed = Math.round((endTime - startTime) / 1000); + + const instance = (globalThis as any).init_pure(); + + this.logService.info("WASM pure SDK loaded in", Math.round(endTime - startTime), "ms"); + + // If it takes 3 seconds or more to load, we want to capture it. + if (elapsed >= 3) { + throw new RecoverableSDKError(instance, elapsed); + } + + return instance; + } +} + /** * SDK client factory with a js fallback for when WASM is not supported. * diff --git a/apps/browser/src/platform/services/sdk/fallback.ts b/apps/browser/src/platform/services/sdk/fallback.ts index 82d292fc9ee..364b505485d 100644 --- a/apps/browser/src/platform/services/sdk/fallback.ts +++ b/apps/browser/src/platform/services/sdk/fallback.ts @@ -1,6 +1,11 @@ import * as sdk from "@bitwarden/sdk-internal"; import * as wasm from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm.js"; +(globalThis as any).init_pure = () => { + (sdk as any).init(wasm); + + return new sdk.BitwardenPure(); +}; (globalThis as any).init_sdk = (...args: ConstructorParameters) => { (sdk as any).init(wasm); diff --git a/apps/browser/src/platform/services/sdk/wasm.ts b/apps/browser/src/platform/services/sdk/wasm.ts index 1977a171e23..02f40f1b9fe 100644 --- a/apps/browser/src/platform/services/sdk/wasm.ts +++ b/apps/browser/src/platform/services/sdk/wasm.ts @@ -1,6 +1,11 @@ import * as sdk from "@bitwarden/sdk-internal"; import * as wasm from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm"; +(globalThis as any).init_pure = () => { + (sdk as any).init(wasm); + + return new sdk.BitwardenPure(); +}; (globalThis as any).init_sdk = (...args: ConstructorParameters) => { (sdk as any).init(wasm); diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 7014d908ac3..7f7c5b99971 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -70,7 +70,10 @@ import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/ke import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; +import { + SdkClientFactory, + SdkPureClientFactory, +} from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { AbstractStorageService, @@ -83,7 +86,10 @@ import { flagEnabled } from "@bitwarden/common/platform/misc/flags"; import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; -import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; +import { + NoopSdkClientFactory, + NoopSdkPureClientFactory, +} from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; import { @@ -144,7 +150,10 @@ import BrowserMemoryStorageService from "../../platform/services/browser-memory- import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service"; import I18nService from "../../platform/services/i18n.service"; import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service"; -import { BrowserSdkClientFactory } from "../../platform/services/sdk/browser-sdk-client-factory"; +import { + BrowserSdkClientFactory, + BrowserSdkPureClientFactory, +} from "../../platform/services/sdk/browser-sdk-client-factory"; import { ForegroundTaskSchedulerService } from "../../platform/services/task-scheduler/foreground-task-scheduler.service"; import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; @@ -584,6 +593,14 @@ const safeProviders: SafeProvider[] = [ flagEnabled("sdk") ? new BrowserSdkClientFactory(logService) : new NoopSdkClientFactory(), deps: [LogService], }), + safeProvider({ + provide: SdkPureClientFactory, + useFactory: (logService) => + flagEnabled("sdk") + ? new BrowserSdkPureClientFactory(logService) + : new NoopSdkPureClientFactory(), + deps: [LogService], + }), safeProvider({ provide: LoginEmailService, useClass: LoginEmailService, diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 2dd1db9fdb6..fa60520a3d3 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -66,7 +66,10 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; +import { + SdkClientFactory, + SdkPureClientFactory, +} from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { ThemeType } from "@bitwarden/common/platform/enums"; import { AppIdService as DefaultAppIdService } from "@bitwarden/common/platform/services/app-id.service"; @@ -74,7 +77,10 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory // eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; -import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; +import { + NoopSdkClientFactory, + NoopSdkPureClientFactory, +} from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; /* eslint-disable import/no-restricted-paths -- Implementation for memory storage */ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; @@ -110,7 +116,7 @@ import { WebProcessReloadService } from "../key-management/services/web-process- import { WebBiometricsService } from "../key-management/web-biometric.service"; import { WebEnvironmentService } from "../platform/web-environment.service"; import { WebMigrationRunner } from "../platform/web-migration-runner"; -import { WebSdkClientFactory } from "../platform/web-sdk-client-factory"; +import { WebSdkClientFactory, WebSdkPureClientFactory } from "../platform/web-sdk-client-factory"; import { WebStorageServiceProvider } from "../platform/web-storage-service.provider"; import { EventService } from "./event.service"; @@ -293,6 +299,11 @@ const safeProviders: SafeProvider[] = [ useClass: flagEnabled("sdk") ? WebSdkClientFactory : NoopSdkClientFactory, deps: [], }), + safeProvider({ + provide: SdkPureClientFactory, + useClass: flagEnabled("sdk") ? WebSdkPureClientFactory : NoopSdkPureClientFactory, + deps: [], + }), safeProvider({ provide: ProcessReloadServiceAbstraction, useClass: WebProcessReloadService, diff --git a/apps/web/src/app/platform/web-sdk-client-factory.ts b/apps/web/src/app/platform/web-sdk-client-factory.ts index 2ebb2bcc10f..22b32a0d996 100644 --- a/apps/web/src/app/platform/web-sdk-client-factory.ts +++ b/apps/web/src/app/platform/web-sdk-client-factory.ts @@ -1,6 +1,19 @@ -import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; +import { + SdkClientFactory, + SdkPureClientFactory, +} from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import * as sdk from "@bitwarden/sdk-internal"; +export class WebSdkPureClientFactory implements SdkPureClientFactory { + async createPureSdkClient(): Promise { + const module = await load(); + + (sdk as any).init(module); + + return Promise.resolve(new sdk.BitwardenPure()); + } +} + /** * SDK client factory with a js fallback for when WASM is not supported. */ diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 0e50cec1b64..87dc3ff4aa8 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -160,7 +160,10 @@ import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwar import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; +import { + SdkClientFactory, + SdkPureClientFactory, +} from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; @@ -181,6 +184,8 @@ import { ConfigApiService } from "@bitwarden/common/platform/services/config/con import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-encrypt.service.implementation"; +import { FallbackBulkEncryptService } from "@bitwarden/common/platform/services/cryptography/fallback-bulk-encrypt.service"; +import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation"; import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; import { DefaultBroadcasterService } from "@bitwarden/common/platform/services/default-broadcaster.service"; import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service"; @@ -886,13 +891,13 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: EncryptService, - useClass: MultithreadEncryptServiceImplementation, - deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES], + useClass: EncryptServiceImplementation, + deps: [SdkPureClientFactory, CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES], }), safeProvider({ provide: BulkEncryptService, - useClass: BulkEncryptServiceImplementation, - deps: [CryptoFunctionServiceAbstraction, LogService], + useClass: FallbackBulkEncryptService, + deps: [EncryptService], }), safeProvider({ provide: EventUploadServiceAbstraction, diff --git a/libs/common/src/platform/abstractions/sdk/sdk-client-factory.ts b/libs/common/src/platform/abstractions/sdk/sdk-client-factory.ts index d684561dacd..f3e9b4c1478 100644 --- a/libs/common/src/platform/abstractions/sdk/sdk-client-factory.ts +++ b/libs/common/src/platform/abstractions/sdk/sdk-client-factory.ts @@ -1,4 +1,4 @@ -import type { BitwardenClient } from "@bitwarden/sdk-internal"; +import type { BitwardenClient, BitwardenPure } from "@bitwarden/sdk-internal"; /** * Factory for creating SDK clients. @@ -8,3 +8,7 @@ export abstract class SdkClientFactory { ...args: ConstructorParameters ): Promise; } + +export abstract class SdkPureClientFactory { + abstract createPureSdkClient(): Promise; +} diff --git a/libs/common/src/platform/models/domain/enc-string.ts b/libs/common/src/platform/models/domain/enc-string.ts index c484c80ee5b..ddfde8a015e 100644 --- a/libs/common/src/platform/models/domain/enc-string.ts +++ b/libs/common/src/platform/models/domain/enc-string.ts @@ -12,7 +12,7 @@ import { SymmetricCryptoKey } from "./symmetric-crypto-key"; export const DECRYPT_ERROR = "[error: cannot decrypt]"; export class EncString implements Encrypted { - encryptedString?: EncryptedString; + encryptedString: EncryptedString; encryptionType?: EncryptionType; decryptedValue?: string; data?: string; 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 0a85b34eba8..ea1cd461274 100644 --- a/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts +++ b/libs/common/src/platform/services/cryptography/encrypt.service.implementation.ts @@ -1,10 +1,14 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore + +// eslint-disable-next-line no-restricted-imports -- TODO MDG: fix this +import { SdkPureClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; + 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, encryptionTypeToString as encryptionTypeName } from "../../enums"; +import { EncryptionType } from "../../enums"; import { Decryptable } from "../../interfaces/decryptable.interface"; import { Encrypted } from "../../interfaces/encrypted"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; @@ -15,6 +19,7 @@ import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; export class EncryptServiceImplementation implements EncryptService { constructor( + protected readonly sdkPureClientFactory: SdkPureClientFactory, protected cryptoFunctionService: CryptoFunctionService, protected logService: LogService, protected logMacFailures: boolean, @@ -76,56 +81,10 @@ 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( - "[Encrypt service] Key has mac key but payload is missing mac bytes. Key type " + - encryptionTypeName(key.encType) + - "Payload type " + - encryptionTypeName(encString.encryptionType), - "Decrypt context: " + decryptContext, - ); - return null; - } + const pure = await this.sdkPureClientFactory.createPureSdkClient(); + const decrypted = pure.crypto().symmetric_decrypt(encString.encryptedString, key.keyB64); - if (key.encType !== encString.encryptionType) { - this.logService.error( - "[Encrypt service] Key encryption type does not match payload encryption type. Key type " + - encryptionTypeName(key.encType) + - "Payload type " + - encryptionTypeName(encString.encryptionType), - "Decrypt context: " + decryptContext, - ); - return null; - } - - const fastParams = this.cryptoFunctionService.aesDecryptFastParameters( - encString.data, - encString.iv, - encString.mac, - key, - ); - if (fastParams.macKey != null && fastParams.mac != null) { - const computedMac = await this.cryptoFunctionService.hmacFast( - fastParams.macData, - fastParams.macKey, - "sha256", - ); - const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac); - if (!macsEqual) { - this.logMacFailed( - "[Encrypt service] MAC comparison failed. Key or payload has changed. Key type " + - encryptionTypeName(key.encType) + - "Payload type " + - encryptionTypeName(encString.encryptionType) + - " Decrypt context: " + - decryptContext, - ); - return null; - } - } - - return await this.cryptoFunctionService.aesDecryptFast(fastParams, "cbc"); + return decrypted; } async decryptToBytes(encThing: Encrypted, key: SymmetricCryptoKey): Promise { @@ -139,64 +98,18 @@ 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( - "[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( - "[Encrypt service] Key encryption type does not match payload encryption type. Key type " + - encryptionTypeName(key.encType) + - " Payload type " + - encryptionTypeName(encThing.encryptionType), - ); - return null; - } - - if (key.macKey != null && encThing.macBytes != null) { - const macData = new Uint8Array(encThing.ivBytes.byteLength + encThing.dataBytes.byteLength); - macData.set(new Uint8Array(encThing.ivBytes), 0); - macData.set(new Uint8Array(encThing.dataBytes), encThing.ivBytes.byteLength); - const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256"); - if (computedMac === null) { - 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( - "[Encrypt service] MAC comparison failed. Key or payload has changed." + - " Key type " + - encryptionTypeName(key.encType) + - " Payload type " + - encryptionTypeName(encThing.encryptionType), - ); - return null; - } - } - - const result = await this.cryptoFunctionService.aesDecrypt( - encThing.dataBytes, - encThing.ivBytes, - key.encKey, - "cbc", + const pure = await this.sdkPureClientFactory.createPureSdkClient(); + const encString = new EncString( + encThing.encryptionType, + Utils.fromBufferToB64(encThing.dataBytes), + Utils.fromBufferToB64(encThing.ivBytes), + Utils.fromBufferToB64(encThing.macBytes), ); + const decrypted = pure + .crypto() + .symmetric_decrypt_to_bytes(encString.encryptedString, key.keyB64); - return result ?? null; + return decrypted ?? null; } async rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise { @@ -262,18 +175,18 @@ export class EncryptServiceImplementation implements EncryptService { } private async aesEncrypt(data: Uint8Array, key: SymmetricCryptoKey): Promise { + const pure = await this.sdkPureClientFactory.createPureSdkClient(); + const encString = new EncString( + pure.crypto().symmetric_encrypt(Utils.fromBufferToUtf8(data), key.keyB64), + ); const obj = new EncryptedObject(); obj.key = key; - obj.iv = await this.cryptoFunctionService.randomBytes(16); - obj.data = await this.cryptoFunctionService.aesEncrypt(data, obj.iv, obj.key.encKey); + obj.iv = encString.ivBytes; + obj.data = encString.dataBytes; if (obj.key.macKey != null) { - const macData = new Uint8Array(obj.iv.byteLength + obj.data.byteLength); - macData.set(new Uint8Array(obj.iv), 0); - macData.set(new Uint8Array(obj.data), obj.iv.byteLength); - obj.mac = await this.cryptoFunctionService.hmac(macData, obj.key.macKey, "sha256"); + obj.mac = encString.macBytes; } - return obj; } diff --git a/libs/common/src/platform/services/cryptography/encrypt.worker.ts b/libs/common/src/platform/services/cryptography/encrypt.worker.ts index a293e1c6bb0..6d78edc92dc 100644 --- a/libs/common/src/platform/services/cryptography/encrypt.worker.ts +++ b/libs/common/src/platform/services/cryptography/encrypt.worker.ts @@ -2,6 +2,9 @@ // @ts-strict-ignore import { Jsonify } from "type-fest"; +// eslint-disable-next-line no-restricted-imports -- TODO MDG: this is a bug in the restricted import rule +import { DefaultSdkPureClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; + import { Decryptable } from "../../interfaces/decryptable.interface"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { ConsoleLogService } from "../console-log.service"; @@ -22,7 +25,13 @@ let encryptService: EncryptServiceImplementation; export function init() { const cryptoFunctionService = new WebCryptoFunctionService(self); const logService = new ConsoleLogService(false); - encryptService = new EncryptServiceImplementation(cryptoFunctionService, logService, true); + const pureSdkFactory = new DefaultSdkPureClientFactory(); + encryptService = new EncryptServiceImplementation( + pureSdkFactory, + cryptoFunctionService, + logService, + true, + ); const bitwardenContainerService = new ContainerService(null, encryptService); bitwardenContainerService.attachToGlobal(self); diff --git a/libs/common/src/platform/services/cryptography/fallback-bulk-encrypt.service.ts b/libs/common/src/platform/services/cryptography/fallback-bulk-encrypt.service.ts index 7a4fd8f3c1d..724162972bc 100644 --- a/libs/common/src/platform/services/cryptography/fallback-bulk-encrypt.service.ts +++ b/libs/common/src/platform/services/cryptography/fallback-bulk-encrypt.service.ts @@ -22,11 +22,11 @@ export class FallbackBulkEncryptService implements BulkEncryptService { items: Decryptable[], key: SymmetricCryptoKey, ): Promise { - if (this.featureFlagEncryptService != null) { - return await this.featureFlagEncryptService.decryptItems(items, key); - } else { - return await this.encryptService.decryptItems(items, key); - } + return await this.encryptService.decryptItems(items, key); + // if (this.featureFlagEncryptService != null) { + // return await this.featureFlagEncryptService.decryptItems(items, key); + // } else { + // } } async setFeatureFlagEncryptService(featureFlagEncryptService: BulkEncryptService) { diff --git a/libs/common/src/platform/services/sdk/default-sdk-client-factory.ts b/libs/common/src/platform/services/sdk/default-sdk-client-factory.ts index 8e99af2efed..4c690e3e198 100644 --- a/libs/common/src/platform/services/sdk/default-sdk-client-factory.ts +++ b/libs/common/src/platform/services/sdk/default-sdk-client-factory.ts @@ -1,7 +1,15 @@ import * as sdk from "@bitwarden/sdk-internal"; import * as module from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm"; -import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory"; +import { SdkClientFactory, SdkPureClientFactory } from "../../abstractions/sdk/sdk-client-factory"; + +export class DefaultSdkPureClientFactory implements SdkPureClientFactory { + async createPureSdkClient(): Promise { + (sdk as any).init(module); + + return Promise.resolve(new sdk.BitwardenPure()); + } +} /** * Directly imports the Bitwarden SDK and initializes it. diff --git a/libs/common/src/platform/services/sdk/noop-sdk-client-factory.ts b/libs/common/src/platform/services/sdk/noop-sdk-client-factory.ts index d7eab7e8dc9..31cb2a95117 100644 --- a/libs/common/src/platform/services/sdk/noop-sdk-client-factory.ts +++ b/libs/common/src/platform/services/sdk/noop-sdk-client-factory.ts @@ -1,6 +1,12 @@ import type { BitwardenClient } from "@bitwarden/sdk-internal"; -import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory"; +import { SdkClientFactory, SdkPureClientFactory } from "../../abstractions/sdk/sdk-client-factory"; + +export class NoopSdkPureClientFactory implements SdkPureClientFactory { + createPureSdkClient(): Promise { + return Promise.reject(new Error("SDK not available")); + } +} /** * Noop SDK client factory.