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

rename password hash to master key hash

This commit is contained in:
Jacob Fink 2023-07-20 11:51:12 -04:00
parent e3c8424f0c
commit 3ba85c3f45
No known key found for this signature in database
GPG Key ID: C2F7ACF05859D008
22 changed files with 64 additions and 62 deletions

View File

@ -185,7 +185,7 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
kdfType,
new KdfConfig(kdfIterations, kdfMemory, kdfParallelism)
);
const newPasswordHash = await this.cryptoService.hashPassword(
const newMasterKeyHash = await this.cryptoService.hashMasterKey(
this.newPassword,
newMasterKey
);
@ -199,7 +199,7 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
// Create request
const request = new OrganizationUserResetPasswordRequest();
request.key = newUserKey[1].encryptedString;
request.newMasterPasswordHash = newPasswordHash;
request.newMasterPasswordHash = newMasterKeyHash;
// Change user's password
return this.organizationUserService.putOrganizationUserResetPassword(

View File

@ -35,7 +35,7 @@ export class RecoverTwoFactorComponent {
request.recoveryCode = this.recoveryCode.replace(/\s/g, "").toLowerCase();
request.email = this.email.trim().toLowerCase();
const key = await this.authService.makePreloginKey(this.masterPassword, request.email);
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, key);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(this.masterPassword, key);
this.formPromise = this.apiService.postTwoFactorRecover(request);
await this.formPromise;
this.platformUtilsService.showToast(

View File

@ -115,15 +115,12 @@ export class EmergencyAccessTakeoverComponent
takeoverResponse.kdfParallelism
)
);
const masterPasswordHash = await this.cryptoService.hashPassword(
this.masterPassword,
masterKey
);
const masterKeyHash = await this.cryptoService.hashMasterKey(this.masterPassword, masterKey);
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, oldUserKey);
const request = new EmergencyAccessPasswordRequest();
request.newMasterPasswordHash = masterPasswordHash;
request.newMasterPasswordHash = masterKeyHash;
request.key = encKey[1].encryptedString;
this.apiService.postEmergencyAccessPassword(this.emergencyAccessId, request);

View File

@ -52,7 +52,10 @@ export class ChangeEmailComponent implements OnInit {
if (!this.tokenSent) {
const request = new EmailTokenRequest();
request.newEmail = this.newEmail;
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
null
);
try {
this.formPromise = this.apiService.postEmailToken(request);
await this.formPromise;
@ -64,7 +67,10 @@ export class ChangeEmailComponent implements OnInit {
const request = new EmailRequest();
request.token = this.token;
request.newEmail = this.newEmail;
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
null
);
const kdf = await this.stateService.getKdfType();
const kdfConfig = await this.stateService.getKdfConfig();
const newMasterKey = await this.cryptoService.makeMasterKey(
@ -73,7 +79,7 @@ export class ChangeEmailComponent implements OnInit {
kdf,
kdfConfig
);
request.newMasterPasswordHash = await this.cryptoService.hashPassword(
request.newMasterPasswordHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
newMasterKey
);

View File

@ -75,7 +75,7 @@ export class ChangeKdfConfirmationComponent {
request.kdfIterations = this.kdfConfig.iterations;
request.kdfMemory = this.kdfConfig.memory;
request.kdfParallelism = this.kdfConfig.parallelism;
request.masterPasswordHash = await this.cryptoService.hashPassword(masterPassword, null);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, null);
const email = await this.stateService.getEmail();
const newMasterKey = await this.cryptoService.makeMasterKey(
masterPassword,
@ -83,7 +83,7 @@ export class ChangeKdfConfirmationComponent {
this.kdf,
this.kdfConfig
);
request.newMasterPasswordHash = await this.cryptoService.hashPassword(
request.newMasterPasswordHash = await this.cryptoService.hashMasterKey(
masterPassword,
newMasterKey
);

View File

@ -189,7 +189,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
newUserKey: [UserKey, EncString]
) {
const request = new PasswordRequest();
request.masterPasswordHash = await this.cryptoService.hashPassword(
request.masterPasswordHash = await this.cryptoService.hashMasterKey(
this.currentMasterPassword,
null
);

View File

@ -78,7 +78,7 @@ export class UpdateKeyComponent {
const request = new UpdateKeyRequest();
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
request.key = newUserKey[1].encryptedString;
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(this.masterPassword, null);
await this.syncService.fullSync(true);

View File

@ -87,7 +87,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
this.kdf,
this.kdfConfig
);
const newMasterPasswordHash = await this.cryptoService.hashPassword(
const newMasterKeyHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
newMasterKey
);
@ -100,7 +100,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
newProtectedUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
}
await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserKey);
await this.performSubmitActions(newMasterKeyHash, newMasterKey, newProtectedUserKey);
}
async setupSubmitActions(): Promise<boolean> {

View File

@ -247,36 +247,36 @@ export class LockComponent implements OnInit, OnDestroy {
kdf,
kdfConfig
);
const storedPasswordHash = await this.cryptoService.getPasswordHash();
const storedPasswordHash = await this.cryptoService.getMasterKeyHash();
let passwordValid = false;
if (storedPasswordHash != null) {
// Offline unlock possible
passwordValid = await this.cryptoService.compareAndUpdatePasswordHash(
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
this.masterPassword,
masterKey
);
} else {
// Online only
const request = new SecretVerificationRequest();
const serverPasswordHash = await this.cryptoService.hashPassword(
const serverKeyHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
masterKey,
HashPurpose.ServerAuthorization
);
request.masterPasswordHash = serverPasswordHash;
request.masterPasswordHash = serverKeyHash;
try {
this.formPromise = this.apiService.postAccountVerifyPassword(request);
const response = await this.formPromise;
this.enforcedMasterPasswordOptions = MasterPasswordPolicyOptions.fromResponse(response);
passwordValid = true;
const localPasswordHash = await this.cryptoService.hashPassword(
const localKeyHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
masterKey,
HashPurpose.LocalAuthorization
);
await this.cryptoService.setPasswordHash(localPasswordHash);
await this.cryptoService.setMasterKeyHash(localKeyHash);
} catch (e) {
this.logService.error(e);
} finally {

View File

@ -102,7 +102,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
try {
// Create Request
const request = new PasswordRequest();
request.masterPasswordHash = await this.cryptoService.hashPassword(
request.masterPasswordHash = await this.cryptoService.hashMasterKey(
this.currentMasterPassword,
null
);

View File

@ -120,7 +120,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
this.kdf,
this.kdfConfig
);
const newPasswordHash = await this.cryptoService.hashPassword(
const newPasswordHash = await this.cryptoService.hashMasterKey(
this.masterPassword,
newMasterKey
);

View File

@ -273,12 +273,12 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
const kdfConfig = DEFAULT_KDF_CONFIG;
const key = await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig);
const newUserKey = await this.cryptoService.makeUserKey(key);
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, key);
const keys = await this.cryptoService.makeKeyPair(newUserKey[0]);
const request = new RegisterRequest(
email,
name,
hashedPassword,
masterKeyHash,
hint,
newUserKey[1].encryptedString,
this.referenceData,

View File

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

View File

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

View File

@ -85,10 +85,10 @@ describe("PasswordLogInStrategy", () => {
authService.makePreloginKey.mockResolvedValue(masterKey);
cryptoService.hashPassword
cryptoService.hashMasterKey
.calledWith(masterPassword, expect.anything(), undefined)
.mockResolvedValue(hashedPassword);
cryptoService.hashPassword
cryptoService.hashMasterKey
.calledWith(masterPassword, expect.anything(), HashPurpose.LocalAuthorization)
.mockResolvedValue(localHashedPassword);
@ -142,7 +142,7 @@ describe("PasswordLogInStrategy", () => {
await passwordLogInStrategy.logIn(credentials);
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setPasswordHash).toHaveBeenCalledWith(localHashedPassword);
expect(cryptoService.setMasterKeyHash).toHaveBeenCalledWith(localHashedPassword);
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);

View File

@ -35,7 +35,7 @@ export class PasswordLogInStrategy extends LogInStrategy {
tokenRequest: PasswordTokenRequest;
private localHashedPassword: string;
private localMasterKeyHash: string;
private masterKey: MasterKey;
/**
@ -97,16 +97,16 @@ export class PasswordLogInStrategy extends LogInStrategy {
this.masterKey = await this.authService.makePreloginKey(masterPassword, email);
// Hash the password early (before authentication) so we don't persist it in memory in plaintext
this.localHashedPassword = await this.cryptoService.hashPassword(
this.localMasterKeyHash = await this.cryptoService.hashMasterKey(
masterPassword,
this.masterKey,
HashPurpose.LocalAuthorization
);
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, this.masterKey);
const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, this.masterKey);
this.tokenRequest = new PasswordTokenRequest(
email,
hashedPassword,
masterKeyHash,
captchaToken,
await this.buildTwoFactor(twoFactor),
await this.buildDeviceRequest()
@ -143,7 +143,7 @@ export class PasswordLogInStrategy extends LogInStrategy {
protected override async setMasterKey(response: IdentityTokenResponse) {
await this.cryptoService.setMasterKey(this.masterKey);
await this.cryptoService.setPasswordHash(this.localHashedPassword);
await this.cryptoService.setMasterKeyHash(this.localMasterKeyHash);
}
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {

View File

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

View File

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

View File

@ -41,7 +41,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
} else {
request.masterPasswordHash = alreadyHashed
? verification.secret
: await this.cryptoService.hashPassword(verification.secret, null);
: await this.cryptoService.hashMasterKey(verification.secret, null);
}
return request;
@ -63,7 +63,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
throw new Error(this.i18nService.t("invalidVerificationCode"));
}
} else {
const passwordValid = await this.cryptoService.compareAndUpdatePasswordHash(
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
verification.secret,
null
);

View File

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

View File

@ -208,7 +208,11 @@ export class CryptoService implements CryptoServiceAbstraction {
return new SymmetricCryptoKey(decUserKey) as UserKey;
}
async hashPassword(password: string, key: MasterKey, hashPurpose?: HashPurpose): Promise<string> {
async hashMasterKey(
password: string,
key: MasterKey,
hashPurpose?: HashPurpose
): Promise<string> {
key ||= await this.getMasterKey();
if (password == null || key == null) {
@ -220,25 +224,22 @@ export class CryptoService implements CryptoServiceAbstraction {
return Utils.fromBufferToB64(hash);
}
async setPasswordHash(keyHash: string): Promise<void> {
async setMasterKeyHash(keyHash: string): Promise<void> {
await this.stateService.setKeyHash(keyHash);
}
async getPasswordHash(): Promise<string> {
async getMasterKeyHash(): Promise<string> {
return await this.stateService.getKeyHash();
}
async clearPasswordHash(userId?: string): Promise<void> {
async clearMasterKeyHash(userId?: string): Promise<void> {
return await this.stateService.setKeyHash(null, { userId: userId });
}
async compareAndUpdatePasswordHash(
masterPassword: string,
masterKey: MasterKey
): Promise<boolean> {
const storedPasswordHash = await this.getPasswordHash();
async compareAndUpdateKeyHash(masterPassword: string, masterKey: MasterKey): Promise<boolean> {
const storedPasswordHash = await this.getMasterKeyHash();
if (masterPassword != null && storedPasswordHash != null) {
const localKeyHash = await this.hashPassword(
const localKeyHash = await this.hashMasterKey(
masterPassword,
masterKey,
HashPurpose.LocalAuthorization
@ -248,13 +249,13 @@ export class CryptoService implements CryptoServiceAbstraction {
}
// TODO: remove serverKeyHash check in 1-2 releases after everyone's keyHash has been updated
const serverKeyHash = await this.hashPassword(
const serverKeyHash = await this.hashMasterKey(
masterPassword,
masterKey,
HashPurpose.ServerAuthorization
);
if (serverKeyHash != null && storedPasswordHash === serverKeyHash) {
await this.setPasswordHash(localKeyHash);
await this.setMasterKeyHash(localKeyHash);
return true;
}
}
@ -565,7 +566,7 @@ export class CryptoService implements CryptoServiceAbstraction {
async clearKeys(userId?: string): Promise<any> {
await this.clearUserKey(true, userId);
await this.clearPasswordHash(userId);
await this.clearMasterKeyHash(userId);
await this.clearOrgKeys(false, userId);
await this.clearProviderKeys(false, userId);
await this.clearKeyPair(false, userId);

View File

@ -2,7 +2,6 @@ import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction }
import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "../../admin-console/enums";
import { TokenService } from "../../auth/abstractions/token.service";
import { KeySuffixOptions } from "../../enums/key-suffix-options.enum";
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { StateService } from "../../platform/abstractions/state.service";
@ -123,6 +122,5 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
async clear(userId?: string): Promise<void> {
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
await this.cryptoService.clearPinKeys(userId);
await this.cryptoService.clearDeprecatedKeys(KeySuffixOptions.Pin, userId);
}
}