diff --git a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts index a720ea1d29d..6dba019ce72 100644 --- a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts +++ b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts @@ -1,11 +1,17 @@ import { Observable } from "rxjs"; +// eslint-disable-next-line no-restricted-imports +import { KdfConfig } from "@bitwarden/key-management"; + import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason"; import { EncString } from "../../../platform/models/domain/enc-string"; import { UserId } from "../../../types/guid"; import { MasterKey, UserKey } from "../../../types/key"; -import { KdfConfig } from "@bitwarden/key-management"; -import { MasterKeyWrappedUserKey, MasterPasswordAuthenticationData, MasterPasswordUnlockData } from "../types/master-password.types"; +import { + MasterKeyWrappedUserKey, + MasterPasswordAuthenticationData, + MasterPasswordUnlockData, +} from "../types/master-password.types"; export abstract class MasterPasswordServiceAbstraction { /** @@ -47,7 +53,6 @@ export abstract class MasterPasswordServiceAbstraction { userKey?: EncString, ) => Promise; - abstract makeMasterPasswordAuthenticationData: ( password: string, kdf: KdfConfig, @@ -69,7 +74,7 @@ export abstract class MasterPasswordServiceAbstraction { userKey: UserKey, ) => Promise; - abstract unwrapMasterKeyWrappedUserKey: ( + abstract unwrapUserKeyFromMasterPasswordUnlockData: ( password: string, masterPasswordUnlockData: MasterPasswordUnlockData, ) => Promise; diff --git a/libs/common/src/key-management/master-password/services/fake-master-password.service.ts b/libs/common/src/key-management/master-password/services/fake-master-password.service.ts index 40cbeda2ff1..d8af3d7b7ff 100644 --- a/libs/common/src/key-management/master-password/services/fake-master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/fake-master-password.service.ts @@ -108,10 +108,10 @@ export class FakeMasterPasswordService implements InternalMasterPasswordServiceA return this.mock.makeMasterKeyWrappedUserKey(password, kdf, salt, userKey); } - unwrapMasterKeyWrappedUserKey( + unwrapUserKeyFromMasterPasswordUnlockData( password: string, masterPasswordUnlockData: MasterPasswordUnlockData, ): Promise { - return this.mock.unwrapMasterKeyWrappedUserKey(password, masterPasswordUnlockData); + return this.mock.unwrapUserKeyFromMasterPasswordUnlockData(password, masterPasswordUnlockData); } } diff --git a/libs/common/src/key-management/master-password/services/master-password.service.spec.ts b/libs/common/src/key-management/master-password/services/master-password.service.spec.ts index 41fee42b984..111f210494f 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.spec.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.spec.ts @@ -277,7 +277,7 @@ describe("MasterPasswordService", () => { it("wraps and unwraps user key with password", async () => { const wrappedKey = await sut.makeMasterKeyWrappedUserKey(password, kdf, salt, userKey); - const unwrappedUserkey = await sut.unwrapMasterKeyWrappedUserKey(password, { + const unwrappedUserkey = await sut.unwrapUserKeyFromMasterPasswordUnlockData(password, { kdf, salt, masterKeyWrappedUserKey: wrappedKey, diff --git a/libs/common/src/key-management/master-password/services/master-password.service.ts b/libs/common/src/key-management/master-password/services/master-password.service.ts index 3a429e8f94d..5440c2ddedb 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.ts @@ -20,7 +20,13 @@ import { MasterKey, UserKey } from "../../../types/key"; import { EncryptService } from "../../crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "../abstractions/master-password.service.abstraction"; import { KdfConfig, KeyService } from "@bitwarden/key-management"; -import { MasterKeyWrappedUserKey, MasterPasswordAuthenticationData, MasterPasswordAuthenticationHash, MasterPasswordSalt, MasterPasswordUnlockData } from "../types/master-password.types"; +import { + MasterKeyWrappedUserKey, + MasterPasswordAuthenticationData, + MasterPasswordAuthenticationHash, + MasterPasswordSalt, + MasterPasswordUnlockData, +} from "../types/master-password.types"; import { PureCrypto } from "@bitwarden/sdk-internal"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { CryptoFunctionService } from "../../crypto/abstractions/crypto-function.service"; @@ -66,7 +72,7 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr private encryptService: EncryptService, private logService: LogService, private cryptoFunctionService: CryptoFunctionService, - ) { } + ) {} /** * @deprecated This will be made private @@ -119,7 +125,6 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr throw new Error("User ID is required."); } - const masterKey = await firstValueFrom(this.masterKey$(userId)); const userKey = await this.getMasterKeyEncryptedUserKey(userId); @@ -250,7 +255,7 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr } /** - * Makes the authentication hash for authenticating to the server with the master password. + * Makes the authentication hash for authenticating to the server with the master password. */ async makeMasterPasswordAuthenticationData( password: string, @@ -259,18 +264,20 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr ): Promise { const SERVER_AUTHENTICATION_HASH_ITERATIONS = 1; - const masterKey = await this.keyGenerationService.deriveKeyFromPassword( + const masterKey = (await this.keyGenerationService.deriveKeyFromPassword( password, salt, kdf, - ) as MasterKey; + )) as MasterKey; - const masterPasswordAuthenticationHash = Utils.fromBufferToB64(await this.cryptoFunctionService.pbkdf2( - masterKey.toEncoded(), - password, - "sha256", - SERVER_AUTHENTICATION_HASH_ITERATIONS, - )) as MasterPasswordAuthenticationHash; + const masterPasswordAuthenticationHash = Utils.fromBufferToB64( + await this.cryptoFunctionService.pbkdf2( + masterKey.toEncoded(), + password, + "sha256", + SERVER_AUTHENTICATION_HASH_ITERATIONS, + ), + ) as MasterPasswordAuthenticationHash; return { kdf, @@ -283,20 +290,37 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr * Creates a MasterPasswordUnlockData bundle that encrypts the user-key with a key derived from the password. The * bundle also contains the KDF settings and salt used to derive the key, which are required to decrypt the user-key later. */ - async makeMasterPasswordUnlockData(password: string, kdf: KdfConfig, salt: MasterPasswordSalt, userKey: UserKey): Promise { + async makeMasterPasswordUnlockData( + password: string, + kdf: KdfConfig, + salt: MasterPasswordSalt, + userKey: UserKey, + ): Promise { return { salt, kdf, - masterKeyWrappedUserKey: await this.makeMasterKeyWrappedUserKey(password, kdf, salt, userKey) + masterKeyWrappedUserKey: await this.makeMasterKeyWrappedUserKey(password, kdf, salt, userKey), }; } /** - * Wraps a user-key with a password provided KDF settings. The same KDF settings and salt must be provided to unwrap the user-key, otherwise it will fail to decrypt. - */ - async makeMasterKeyWrappedUserKey(password: string, kdf: KdfConfig, salt: MasterPasswordSalt, userKey: UserKey): Promise { + * Wraps a user-key with a password provided KDF settings. The same KDF settings and salt must be provided to unwrap the user-key, otherwise it will fail to decrypt. + */ + async makeMasterKeyWrappedUserKey( + password: string, + kdf: KdfConfig, + salt: MasterPasswordSalt, + userKey: UserKey, + ): Promise { await SdkLoadService.Ready; - return new EncString(PureCrypto.encrypt_user_key_with_master_password(userKey.toEncoded(), password, salt, kdf.toSdkConfig())) as MasterKeyWrappedUserKey; + return new EncString( + PureCrypto.encrypt_user_key_with_master_password( + userKey.toEncoded(), + password, + salt, + kdf.toSdkConfig(), + ), + ) as MasterKeyWrappedUserKey; } /** @@ -304,14 +328,19 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr * @throws If the encryption type is not supported. * @throws If the password, KDF, or salt don't match the original wrapping parameters. */ - async unwrapMasterKeyWrappedUserKey(password: string, masterPasswordUnlockData: MasterPasswordUnlockData): Promise { + async unwrapUserKeyFromMasterPasswordUnlockData( + password: string, + masterPasswordUnlockData: MasterPasswordUnlockData, + ): Promise { await SdkLoadService.Ready; - const userKey = new SymmetricCryptoKey(PureCrypto.decrypt_user_key_with_master_password( - masterPasswordUnlockData.masterKeyWrappedUserKey!.encryptedString, - password, - masterPasswordUnlockData.salt, - masterPasswordUnlockData.kdf.toSdkConfig(), - )); + const userKey = new SymmetricCryptoKey( + PureCrypto.decrypt_user_key_with_master_password( + masterPasswordUnlockData.masterKeyWrappedUserKey!.encryptedString, + password, + masterPasswordUnlockData.salt, + masterPasswordUnlockData.kdf.toSdkConfig(), + ), + ); return userKey as UserKey; } }