1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-22 21:21:35 +01:00

rename key hash to password hash on crypto service

This commit is contained in:
Jacob Fink 2023-07-06 12:38:36 -04:00
parent b4fd44320d
commit 84874fdd11
No known key found for this signature in database
GPG Key ID: C2F7ACF05859D008
10 changed files with 45 additions and 42 deletions

View File

@ -120,7 +120,7 @@ export class LockComponent implements OnInit, OnDestroy {
const userKey = await this.cryptoService.getUserKeyFromStorage(KeySuffixOptions.Biometric); const userKey = await this.cryptoService.getUserKeyFromStorage(KeySuffixOptions.Biometric);
if (userKey) { if (userKey) {
await this.setKeyAndContinue(userKey, false); await this.setUserKeyAndContinue(userKey, false);
} }
return !!userKey; return !!userKey;
@ -198,7 +198,7 @@ export class LockComponent implements OnInit, OnDestroy {
failed = decryptedPin !== this.pin; failed = decryptedPin !== this.pin;
if (!failed) { if (!failed) {
await this.setKeyAndContinue(userKey); await this.setUserKeyAndContinue(userKey);
} }
} catch { } catch {
failed = true; failed = true;
@ -240,36 +240,36 @@ export class LockComponent implements OnInit, OnDestroy {
kdf, kdf,
kdfConfig kdfConfig
); );
const storedKeyHash = await this.cryptoService.getKeyHash(); const storedPasswordHash = await this.cryptoService.getPasswordHash();
let passwordValid = false; let passwordValid = false;
if (storedKeyHash != null) { if (storedPasswordHash != null) {
// Offline unlock possible // Offline unlock possible
passwordValid = await this.cryptoService.compareAndUpdateKeyHash( passwordValid = await this.cryptoService.compareAndUpdatePasswordHash(
this.masterPassword, this.masterPassword,
masterKey masterKey
); );
} else { } else {
// Online only // Online only
const request = new SecretVerificationRequest(); const request = new SecretVerificationRequest();
const serverKeyHash = await this.cryptoService.hashPassword( const serverPasswordHash = await this.cryptoService.hashPassword(
this.masterPassword, this.masterPassword,
masterKey, masterKey,
HashPurpose.ServerAuthorization HashPurpose.ServerAuthorization
); );
request.masterPasswordHash = serverKeyHash; request.masterPasswordHash = serverPasswordHash;
try { try {
this.formPromise = this.apiService.postAccountVerifyPassword(request); this.formPromise = this.apiService.postAccountVerifyPassword(request);
const response = await this.formPromise; const response = await this.formPromise;
this.enforcedMasterPasswordOptions = MasterPasswordPolicyOptions.fromResponse(response); this.enforcedMasterPasswordOptions = MasterPasswordPolicyOptions.fromResponse(response);
passwordValid = true; passwordValid = true;
const localKeyHash = await this.cryptoService.hashPassword( const localPasswordHash = await this.cryptoService.hashPassword(
this.masterPassword, this.masterPassword,
masterKey, masterKey,
HashPurpose.LocalAuthorization HashPurpose.LocalAuthorization
); );
await this.cryptoService.setKeyHash(localKeyHash); await this.cryptoService.setPasswordHash(localPasswordHash);
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);
} finally { } finally {
@ -288,10 +288,10 @@ export class LockComponent implements OnInit, OnDestroy {
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey); const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setMasterKey(masterKey); await this.cryptoService.setMasterKey(masterKey);
await this.setKeyAndContinue(userKey, true); await this.setUserKeyAndContinue(userKey, true);
} }
private async setKeyAndContinue(key: UserKey, evaluatePasswordAfterUnlock = false) { private async setUserKeyAndContinue(key: UserKey, evaluatePasswordAfterUnlock = false) {
await this.cryptoService.setUserKey(key); await this.cryptoService.setUserKey(key);
await this.doContinue(evaluatePasswordAfterUnlock); await this.doContinue(evaluatePasswordAfterUnlock);
} }

View File

@ -182,11 +182,11 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
await this.cryptoService.setUserKey(userKey[0]); await this.cryptoService.setUserKey(userKey[0]);
await this.cryptoService.setPrivateKey(keyPair[1].encryptedString); await this.cryptoService.setPrivateKey(keyPair[1].encryptedString);
const localKeyHash = await this.cryptoService.hashPassword( const localPasswordHash = await this.cryptoService.hashPassword(
this.masterPassword, this.masterPassword,
masterKey, masterKey,
HashPurpose.LocalAuthorization HashPurpose.LocalAuthorization
); );
await this.cryptoService.setKeyHash(localKeyHash); await this.cryptoService.setPasswordHash(localPasswordHash);
} }
} }

View File

@ -27,7 +27,7 @@ export class PasswordRepromptComponent {
} }
async submit() { async submit() {
if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) { if (!(await this.cryptoService.compareAndUpdatePasswordHash(this.masterPassword, null))) {
this.platformUtilsService.showToast( this.platformUtilsService.showToast(
"error", "error",
this.i18nService.t("errorOccurred"), this.i18nService.t("errorOccurred"),

View File

@ -142,7 +142,7 @@ describe("PasswordLogInStrategy", () => {
await passwordLogInStrategy.logIn(credentials); await passwordLogInStrategy.logIn(credentials);
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey); expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localHashedPassword); expect(cryptoService.setPasswordHash).toHaveBeenCalledWith(localHashedPassword);
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key); expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey); expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey); expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);

View File

@ -143,7 +143,7 @@ export class PasswordLogInStrategy extends LogInStrategy {
protected override async setMasterKey(response: IdentityTokenResponse) { protected override async setMasterKey(response: IdentityTokenResponse) {
await this.cryptoService.setMasterKey(this.masterKey); await this.cryptoService.setMasterKey(this.masterKey);
await this.cryptoService.setKeyHash(this.localHashedPassword); await this.cryptoService.setPasswordHash(this.localHashedPassword);
} }
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> { protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {

View File

@ -93,7 +93,7 @@ describe("SsoLogInStrategy", () => {
await passwordlessLoginStrategy.logIn(credentials); await passwordlessLoginStrategy.logIn(credentials);
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey); expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localPasswordHash); expect(cryptoService.setPasswordHash).toHaveBeenCalledWith(localPasswordHash);
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key); expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey); expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey); expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);

View File

@ -81,7 +81,7 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
protected override async setMasterKey(response: IdentityTokenResponse) { protected override async setMasterKey(response: IdentityTokenResponse) {
await this.cryptoService.setMasterKey(this.passwordlessCredentials.decKey); await this.cryptoService.setMasterKey(this.passwordlessCredentials.decKey);
await this.cryptoService.setKeyHash(this.passwordlessCredentials.localPasswordHash); await this.cryptoService.setPasswordHash(this.passwordlessCredentials.localPasswordHash);
} }
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> { protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {

View File

@ -61,7 +61,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
throw new Error(this.i18nService.t("invalidVerificationCode")); throw new Error(this.i18nService.t("invalidVerificationCode"));
} }
} else { } else {
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash( const passwordValid = await this.cryptoService.compareAndUpdatePasswordHash(
verification.secret, verification.secret,
null null
); );

View File

@ -155,28 +155,28 @@ export abstract class CryptoService {
*/ */
hashPassword: (password: string, key: MasterKey, hashPurpose?: HashPurpose) => Promise<string>; hashPassword: (password: string, key: MasterKey, hashPurpose?: HashPurpose) => Promise<string>;
/** /**
* Sets the user's key hash * Sets the user's master password hash
* @param keyHash The user's key hash to set * @param keyHash The user's master password hash to set
*/ */
setKeyHash: (keyHash: string) => Promise<void>; setPasswordHash: (keyHash: string) => Promise<void>;
/** /**
* @returns The user's key hash * @returns The user's master password hash
*/ */
getKeyHash: () => Promise<string>; getPasswordHash: () => Promise<string>;
/** /**
* Clears the user's stored key hash * Clears the user's stored master password hash
* @param userId The desired user * @param userId The desired user
*/ */
clearKeyHash: () => Promise<void>; clearPasswordHash: () => Promise<void>;
/** /**
* Compares the provided master password to the stored key hash and updates * Compares the provided master password to the stored password hash and server password hash.
* if the stored hash is outdated * Updates the stored hash if outdated.
* @param masterPassword The user's master password * @param masterPassword The user's master password
* @param key The user's master key * @param key The user's master key
* @returns True if the provided master password matches either the stored * @returns True if the provided master password matches either the stored
* key hash * key hash or the server key hash
*/ */
compareAndUpdateKeyHash: (masterPassword: string, key: MasterKey) => Promise<boolean>; compareAndUpdatePasswordHash: (masterPassword: string, masterKey: MasterKey) => Promise<boolean>;
/** /**
* Stores the encrypted organization keys and clears any decrypted * Stores the encrypted organization keys and clears any decrypted
* organization keys currently in memory * organization keys currently in memory

View File

@ -220,38 +220,41 @@ export class CryptoService implements CryptoServiceAbstraction {
return Utils.fromBufferToB64(hash); return Utils.fromBufferToB64(hash);
} }
async setKeyHash(keyHash: string): Promise<void> { async setPasswordHash(keyHash: string): Promise<void> {
await this.stateService.setKeyHash(keyHash); await this.stateService.setKeyHash(keyHash);
} }
async getKeyHash(): Promise<string> { async getPasswordHash(): Promise<string> {
return await this.stateService.getKeyHash(); return await this.stateService.getKeyHash();
} }
async clearKeyHash(userId?: string): Promise<void> { async clearPasswordHash(userId?: string): Promise<void> {
return await this.stateService.setKeyHash(null, { userId: userId }); return await this.stateService.setKeyHash(null, { userId: userId });
} }
async compareAndUpdateKeyHash(masterPassword: string, key: MasterKey): Promise<boolean> { async compareAndUpdatePasswordHash(
const storedKeyHash = await this.getKeyHash(); masterPassword: string,
if (masterPassword != null && storedKeyHash != null) { masterKey: MasterKey
): Promise<boolean> {
const storedPasswordHash = await this.getPasswordHash();
if (masterPassword != null && storedPasswordHash != null) {
const localKeyHash = await this.hashPassword( const localKeyHash = await this.hashPassword(
masterPassword, masterPassword,
key, masterKey,
HashPurpose.LocalAuthorization HashPurpose.LocalAuthorization
); );
if (localKeyHash != null && storedKeyHash === localKeyHash) { if (localKeyHash != null && storedPasswordHash === localKeyHash) {
return true; return true;
} }
// TODO: remove serverKeyHash check in 1-2 releases after everyone's keyHash has been updated // TODO: remove serverKeyHash check in 1-2 releases after everyone's keyHash has been updated
const serverKeyHash = await this.hashPassword( const serverKeyHash = await this.hashPassword(
masterPassword, masterPassword,
key, masterKey,
HashPurpose.ServerAuthorization HashPurpose.ServerAuthorization
); );
if (serverKeyHash != null && storedKeyHash === serverKeyHash) { if (serverKeyHash != null && storedPasswordHash === serverKeyHash) {
await this.setKeyHash(localKeyHash); await this.setPasswordHash(localKeyHash);
return true; return true;
} }
} }
@ -561,7 +564,7 @@ export class CryptoService implements CryptoServiceAbstraction {
async clearKeys(userId?: string): Promise<any> { async clearKeys(userId?: string): Promise<any> {
await this.clearUserKey(true, userId); await this.clearUserKey(true, userId);
await this.clearKeyHash(userId); await this.clearPasswordHash(userId);
await this.clearOrgKeys(false, userId); await this.clearOrgKeys(false, userId);
await this.clearProviderKeys(false, userId); await this.clearProviderKeys(false, userId);
await this.clearKeyPair(false, userId); await this.clearKeyPair(false, userId);