1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PM-23230] Implement KDF Change Service (#15748)

* Add new mp service api

* Fix tests

* Add test coverage

* Add newline

* Fix type

* Rename to "unwrapUserKeyFromMasterPasswordUnlockData"

* Fix build

* Fix build on cli

* Fix linting

* Re-sort spec

* Add tests

* Fix test and build issues

* Fix build

* Clean up

* Remove introduced function

* Clean up comments

* Fix abstract class types

* Fix comments

* Cleanup

* Cleanup

* Update libs/common/src/key-management/master-password/types/master-password.types.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/services/master-password.service.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/types/master-password.types.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Add comments

* Fix build

* Add arg null check

* Cleanup

* Fix build

* Fix build on browser

* Implement KDF change service

* Deprecate encryptUserKeyWithMasterKey

* Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Add tests for null params

* Fix builds

* Cleanup and deprecate more functions

* Fix formatting

* Prettier

* Clean up

* Update libs/key-management/src/abstractions/key.service.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Make emailToSalt private and expose abstract saltForUser

* Add tests

* Add docs

* Fix build

* Fix tests

* Fix tests

* Address feedback and fix primitive obsession

* Consolidate active account checks in change kdf confirmation component

* Update libs/common/src/key-management/kdf/services/change-kdf-service.spec.ts

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Add defensive parameter checks

* Add tests

* Add comment for follow-up epic

* Move change kdf service, remove abstraction and add api service

* Fix test

* Drop redundant null check

* Address feedback

* Add throw on empty password

* Fix tests

* Mark change kdf service as internal

* Add abstract classes

* Switch to abstraction

* use sdk EncString in MasterPasswordUnlockData

* fix remaining tests

---------

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
Co-authored-by: Jake Fink <jfink@bitwarden.com>
This commit is contained in:
Bernd Schoolmann
2025-09-24 05:10:54 +09:00
committed by GitHub
parent 6001980dc5
commit 4b73198ce5
33 changed files with 507 additions and 117 deletions

View File

@@ -303,6 +303,14 @@ export class InputPasswordComponent implements OnInit {
throw new Error("KdfConfig is required to create master key.");
}
const salt =
this.userId != null
? await firstValueFrom(this.masterPasswordService.saltForUser$(this.userId))
: this.masterPasswordService.emailToSalt(this.email);
if (salt == null) {
throw new Error("Salt is required to create master key.");
}
// 2. Verify current password is correct (if necessary)
if (
this.flow === InputPasswordFlow.ChangePassword ||
@@ -348,6 +356,7 @@ export class InputPasswordComponent implements OnInit {
const passwordInputResult: PasswordInputResult = {
newPassword,
salt,
newMasterKey,
newServerMasterKeyHash,
newLocalMasterKeyHash,

View File

@@ -1,18 +1,26 @@
import { MasterPasswordSalt } from "@bitwarden/common/key-management/master-password/types/master-password.types";
import { MasterKey } from "@bitwarden/common/types/key";
import { KdfConfig } from "@bitwarden/key-management";
export interface PasswordInputResult {
currentPassword?: string;
newPassword: string;
kdfConfig?: KdfConfig;
salt?: MasterPasswordSalt;
newPasswordHint?: string;
rotateUserKey?: boolean;
/** @deprecated This low-level cryptographic state will be removed. It will be replaced by high level calls to masterpassword service, in the consumers of this interface. */
currentMasterKey?: MasterKey;
/** @deprecated */
currentServerMasterKeyHash?: string;
/** @deprecated */
currentLocalMasterKeyHash?: string;
newPassword: string;
newPasswordHint?: string;
/** @deprecated */
newMasterKey?: MasterKey;
/** @deprecated */
newServerMasterKeyHash?: string;
/** @deprecated */
newLocalMasterKeyHash?: string;
kdfConfig?: KdfConfig;
rotateUserKey?: boolean;
}

View File

@@ -38,7 +38,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { FakeAccountService, makeEncString, mockAccountServiceWith } from "@bitwarden/common/spec";
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
import {
PasswordStrengthServiceAbstraction,
PasswordStrengthService,
@@ -61,7 +61,7 @@ const masterPassword = "password";
const deviceId = Utils.newGuid();
const accessToken = "ACCESS_TOKEN";
const refreshToken = "REFRESH_TOKEN";
const encryptedUserKey = makeEncString("USER_KEY");
const encryptedUserKey = "USER_KEY";
const privateKey = "PRIVATE_KEY";
const kdf = 0;
const kdfIterations = 10000;
@@ -76,7 +76,7 @@ const defaultUserDecryptionOptionsServerResponse: IUserDecryptionOptionsServerRe
KdfType: kdf,
Iterations: kdfIterations,
},
MasterKeyEncryptedUserKey: encryptedUserKey.encryptedString,
MasterKeyEncryptedUserKey: encryptedUserKey,
},
};
@@ -99,7 +99,7 @@ export function identityTokenResponseFactory(
ForcePasswordReset: false,
Kdf: kdf,
KdfIterations: kdfIterations,
Key: encryptedUserKey.encryptedString,
Key: encryptedUserKey,
PrivateKey: privateKey,
ResetMasterPassword: false,
access_token: accessToken,