diff --git a/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts b/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts index 55f935c575e..23884df6708 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts @@ -23,7 +23,10 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + SymmetricCryptoKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; @Component({ @@ -173,23 +176,29 @@ export class ResetPasswordComponent implements OnInit, OnDestroy { // Decrypt User's Reset Password Key to get EncKey const decValue = await this.cryptoService.rsaDecrypt(resetPasswordKey, decPrivateKey); - const userEncKey = new SymmetricCryptoKey(decValue); + const existingUserSymKey = new SymmetricCryptoKey(decValue) as UserSymKey; - // Create new key and hash new password - const newKey = await this.cryptoService.makeKey( + // Create new master key and hash new password + const newMasterKey = await this.cryptoService.makeMasterKey( this.newPassword, this.email.trim().toLowerCase(), kdfType, new KdfConfig(kdfIterations, kdfMemory, kdfParallelism) ); - const newPasswordHash = await this.cryptoService.hashPassword(this.newPassword, newKey); + const newPasswordHash = await this.cryptoService.hashPassword( + this.newPassword, + newMasterKey + ); - // Create new encKey for the User - const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey); + // Create new encrypted user symmetric key for the User + const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey( + newMasterKey, + existingUserSymKey + ); // Create request const request = new OrganizationUserResetPasswordRequest(); - request.key = newEncKey[1].encryptedString; + request.key = newUserSymKey[1].encryptedString; request.newMasterPasswordHash = newPasswordHash; // Change user's password diff --git a/apps/web/src/app/settings/change-email.component.ts b/apps/web/src/app/settings/change-email.component.ts index c28bf3dcfd6..40f1be17115 100644 --- a/apps/web/src/app/settings/change-email.component.ts +++ b/apps/web/src/app/settings/change-email.component.ts @@ -67,7 +67,7 @@ export class ChangeEmailComponent implements OnInit { request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null); const kdf = await this.stateService.getKdfType(); const kdfConfig = await this.stateService.getKdfConfig(); - const newKey = await this.cryptoService.makeKey( + const newMasterKey = await this.cryptoService.makeMasterKey( this.masterPassword, this.newEmail, kdf, @@ -75,10 +75,10 @@ export class ChangeEmailComponent implements OnInit { ); request.newMasterPasswordHash = await this.cryptoService.hashPassword( this.masterPassword, - newKey + newMasterKey ); - const newEncKey = await this.cryptoService.remakeEncKey(newKey); - request.key = newEncKey[1].encryptedString; + const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(newMasterKey); + request.key = newUserSymKey[1].encryptedString; try { this.formPromise = this.apiService.postEmail(request); await this.formPromise; diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index 8b57c6cfb60..556d417d532 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -23,7 +23,11 @@ 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + MasterKey, + SymmetricCryptoKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SendWithIdRequest } from "@bitwarden/common/tools/send/models/request/send-with-id.request"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; @@ -137,8 +141,8 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { } async submit() { - const hasEncKey = await this.cryptoService.hasEncKey(); - if (!hasEncKey) { + const hasUserKey = await this.cryptoService.hasUserKey(); + if (!hasUserKey) { this.platformUtilsService.showToast("error", null, this.i18nService.t("updateKey")); return; } @@ -179,8 +183,8 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { async performSubmitActions( newMasterPasswordHash: string, - newKey: SymmetricCryptoKey, - newEncKey: [SymmetricCryptoKey, EncString] + newMasterKey: MasterKey, + newUserKey: [UserSymKey, EncString] ) { const request = new PasswordRequest(); request.masterPasswordHash = await this.cryptoService.hashPassword( @@ -189,12 +193,12 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { ); request.masterPasswordHint = this.masterPasswordHint; request.newMasterPasswordHash = newMasterPasswordHash; - request.key = newEncKey[1].encryptedString; + request.key = newUserKey[1].encryptedString; try { if (this.rotateEncKey) { this.formPromise = this.apiService.postPassword(request).then(() => { - return this.updateKey(newKey, request.newMasterPasswordHash); + return this.updateKey(newMasterKey, request.newMasterPasswordHash); }); } else { this.formPromise = this.apiService.postPassword(request); @@ -213,16 +217,16 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { } } - private async updateKey(key: SymmetricCryptoKey, masterPasswordHash: string) { - const encKey = await this.cryptoService.makeEncKey(key); + private async updateKey(masterKey: MasterKey, masterPasswordHash: string) { + const userSymKey = await this.cryptoService.makeUserSymKey(masterKey); const privateKey = await this.cryptoService.getPrivateKey(); let encPrivateKey: EncString = null; if (privateKey != null) { - encPrivateKey = await this.cryptoService.encrypt(privateKey, encKey[0]); + encPrivateKey = await this.cryptoService.encrypt(privateKey, userSymKey[0]); } const request = new UpdateKeyRequest(); request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null; - request.key = encKey[1].encryptedString; + request.key = userSymKey[1].encryptedString; request.masterPasswordHash = masterPasswordHash; const folders = await firstValueFrom(this.folderService.folderViews$); @@ -230,7 +234,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { if (folders[i].id == null) { continue; } - const folder = await this.folderService.encrypt(folders[i], encKey[0]); + const folder = await this.folderService.encrypt(folders[i], userSymKey[0]); request.folders.push(new FolderWithIdRequest(folder)); } @@ -240,24 +244,24 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { continue; } - const cipher = await this.cipherService.encrypt(ciphers[i], encKey[0]); + const cipher = await this.cipherService.encrypt(ciphers[i], userSymKey[0]); request.ciphers.push(new CipherWithIdRequest(cipher)); } const sends = await firstValueFrom(this.sendService.sends$); await Promise.all( sends.map(async (send) => { - const cryptoKey = await this.cryptoService.decryptToBytes(send.key, null); - send.key = (await this.cryptoService.encrypt(cryptoKey, encKey[0])) ?? send.key; + const sendKey = await this.cryptoService.decryptToBytes(send.key, null); + send.key = (await this.cryptoService.encrypt(sendKey, userSymKey[0])) ?? send.key; request.sends.push(new SendWithIdRequest(send)); }) ); await this.apiService.postAccountKey(request); - await this.updateEmergencyAccesses(encKey[0]); + await this.updateEmergencyAccesses(userSymKey[0]); - await this.updateAllResetPasswordKeys(encKey[0], masterPasswordHash); + await this.updateAllResetPasswordKeys(userSymKey[0], masterPasswordHash); } private async updateEmergencyAccesses(encKey: SymmetricCryptoKey) { @@ -285,7 +289,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { } } - private async updateAllResetPasswordKeys(encKey: SymmetricCryptoKey, masterPasswordHash: string) { + private async updateAllResetPasswordKeys(userSymKey: UserSymKey, masterPasswordHash: string) { const orgs = await this.organizationService.getAll(); for (const org of orgs) { @@ -299,7 +303,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { const publicKey = Utils.fromB64ToArray(response?.publicKey); // Re-enroll - encrypt user's encKey.key with organization public key - const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer); + const encryptedKey = await this.cryptoService.rsaEncrypt(userSymKey.key, publicKey.buffer); // Create/Execute request const request = new OrganizationUserResetPasswordEnrollmentRequest(); diff --git a/libs/angular/src/auth/components/change-password.component.ts b/libs/angular/src/auth/components/change-password.component.ts index 2e440b984d3..57d3cbff87d 100644 --- a/libs/angular/src/auth/components/change-password.component.ts +++ b/libs/angular/src/auth/components/change-password.component.ts @@ -12,7 +12,10 @@ 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + MasterKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog"; @@ -79,23 +82,30 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { if (this.kdfConfig == null) { this.kdfConfig = await this.stateService.getKdfConfig(); } - const key = await this.cryptoService.makeKey( + + // Create new master key + const newMasterKey = await this.cryptoService.makeMasterKey( this.masterPassword, email.trim().toLowerCase(), this.kdf, this.kdfConfig ); - const masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, key); + const newMasterPasswordHash = await this.cryptoService.hashPassword( + this.masterPassword, + newMasterKey + ); - let encKey: [SymmetricCryptoKey, EncString] = null; - const existingEncKey = await this.cryptoService.getEncKey(); - if (existingEncKey == null) { - encKey = await this.cryptoService.makeEncKey(key); + let newProtectedUserSymKey: [UserSymKey, EncString] = null; + const userSymKey = await this.cryptoService.getUserKeyFromMemory(); + if (userSymKey == null) { + newProtectedUserSymKey = await this.cryptoService.makeUserSymKey(newMasterKey); } else { - encKey = await this.cryptoService.remakeEncKey(key); + newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey( + newMasterKey + ); } - await this.performSubmitActions(masterPasswordHash, key, encKey); + await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserSymKey); } async setupSubmitActions(): Promise { @@ -106,8 +116,8 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { async performSubmitActions( masterPasswordHash: string, - key: SymmetricCryptoKey, - encKey: [SymmetricCryptoKey, EncString] + masterKey: MasterKey, + userSymKey: [UserSymKey, EncString] ) { // Override in sub-class } diff --git a/libs/angular/src/auth/components/update-password.component.ts b/libs/angular/src/auth/components/update-password.component.ts index 9a6e98156a6..1fdc7a6a15f 100644 --- a/libs/angular/src/auth/components/update-password.component.ts +++ b/libs/angular/src/auth/components/update-password.component.ts @@ -14,7 +14,10 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + MasterKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { Verification } from "@bitwarden/common/types/verification"; @@ -96,8 +99,8 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { async performSubmitActions( masterPasswordHash: string, - key: SymmetricCryptoKey, - encKey: [SymmetricCryptoKey, EncString] + masterKey: MasterKey, + userSymKey: [UserSymKey, EncString] ) { try { // Create Request @@ -107,7 +110,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { null ); request.newMasterPasswordHash = masterPasswordHash; - request.key = encKey[1].encryptedString; + request.key = userSymKey[1].encryptedString; // Update user's password this.apiService.postPassword(request); diff --git a/libs/angular/src/auth/components/update-temp-password.component.ts b/libs/angular/src/auth/components/update-temp-password.component.ts index 34833c3bbf3..6950c416e9e 100644 --- a/libs/angular/src/auth/components/update-temp-password.component.ts +++ b/libs/angular/src/auth/components/update-temp-password.component.ts @@ -16,7 +16,10 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + MasterKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { Verification } from "@bitwarden/common/types/verification"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @@ -114,21 +117,27 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { try { // Create new key and hash new password - const newKey = await this.cryptoService.makeKey( + const newMasterKey = await this.cryptoService.makeMasterKey( this.masterPassword, this.email.trim().toLowerCase(), this.kdf, this.kdfConfig ); - const newPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, newKey); + const newPasswordHash = await this.cryptoService.hashPassword( + this.masterPassword, + newMasterKey + ); - // Grab user's current enc key - const userEncKey = await this.cryptoService.getEncKey(); + // Grab user's symmetric key + const userKey = await this.cryptoService.getUserKeyFromMemory(); - // Create new encKey for the User - const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey); + // Encrypt user's symmetric key with new master key + const newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey( + newMasterKey, + userKey + ); - await this.performSubmitActions(newPasswordHash, newKey, newEncKey); + await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserSymKey); } catch (e) { this.logService.error(e); } @@ -136,16 +145,16 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { async performSubmitActions( masterPasswordHash: string, - key: SymmetricCryptoKey, - encKey: [SymmetricCryptoKey, EncString] + masterKey: MasterKey, + userSymKey: [UserSymKey, EncString] ) { try { switch (this.reason) { case ForceResetPasswordReason.AdminForcePasswordReset: - this.formPromise = this.updateTempPassword(masterPasswordHash, encKey); + this.formPromise = this.updateTempPassword(masterPasswordHash, userSymKey); break; case ForceResetPasswordReason.WeakMasterPassword: - this.formPromise = this.updatePassword(masterPasswordHash, encKey); + this.formPromise = this.updatePassword(masterPasswordHash, userSymKey); break; } @@ -169,27 +178,24 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { } private async updateTempPassword( masterPasswordHash: string, - encKey: [SymmetricCryptoKey, EncString] + userSymKey: [UserSymKey, EncString] ) { const request = new UpdateTempPasswordRequest(); - request.key = encKey[1].encryptedString; + request.key = userSymKey[1].encryptedString; request.newMasterPasswordHash = masterPasswordHash; request.masterPasswordHint = this.hint; return this.apiService.putUpdateTempPassword(request); } - private async updatePassword( - newMasterPasswordHash: string, - encKey: [SymmetricCryptoKey, EncString] - ) { + private async updatePassword(newMasterPasswordHash: string, userSymKey: [UserSymKey, EncString]) { const request = await this.userVerificationService.buildRequest( this.verification, PasswordRequest ); request.masterPasswordHint = this.hint; request.newMasterPasswordHash = newMasterPasswordHash; - request.key = encKey[1].encryptedString; + request.key = userSymKey[1].encryptedString; return this.apiService.postPassword(request); } diff --git a/libs/angular/src/components/set-password.component.ts b/libs/angular/src/components/set-password.component.ts index a4ae3edb80a..1f653cca53b 100644 --- a/libs/angular/src/components/set-password.component.ts +++ b/libs/angular/src/components/set-password.component.ts @@ -18,7 +18,10 @@ 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { + MasterKey, + UserSymKey, +} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @@ -101,16 +104,16 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { async performSubmitActions( masterPasswordHash: string, - key: SymmetricCryptoKey, - encKey: [SymmetricCryptoKey, EncString] + masterKey: MasterKey, + userKey: [UserSymKey, EncString] ) { - const keys = await this.cryptoService.makeKeyPair(encKey[0]); + const newKeyPair = await this.cryptoService.makeKeyPair(userKey[0]); const request = new SetPasswordRequest( masterPasswordHash, - encKey[1].encryptedString, + userKey[1].encryptedString, this.hint, this.identifier, - new KeysRequest(keys[0], keys[1].encryptedString), + new KeysRequest(newKeyPair[0], newKeyPair[1].encryptedString), this.kdf, this.kdfConfig.iterations, this.kdfConfig.memory, @@ -121,7 +124,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { this.formPromise = this.apiService .setPassword(request) .then(async () => { - await this.onSetPasswordSuccess(key, encKey, keys); + await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair); return this.organizationApiService.getKeys(this.orgId); }) .then(async (response) => { @@ -131,16 +134,16 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { const userId = await this.stateService.getUserId(); const publicKey = Utils.fromB64ToArray(response.publicKey); - // RSA Encrypt user's encKey.key with organization public key - const userEncKey = await this.cryptoService.getEncKey(); - const encryptedKey = await this.cryptoService.rsaEncrypt( - userEncKey.key, + // RSA Encrypt user's symmetric key with organization public key + const userKey = await this.cryptoService.getUserKeyFromMemory(); + const encryptedUserKey = await this.cryptoService.rsaEncrypt( + userKey.key, publicKey.buffer ); const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest(); resetRequest.masterPasswordHash = masterPasswordHash; - resetRequest.resetPasswordKey = encryptedKey.encryptedString; + resetRequest.resetPasswordKey = encryptedUserKey.encryptedString; return this.organizationUserService.putOrganizationUserResetPasswordEnrollment( this.orgId, @@ -150,7 +153,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { }); } else { this.formPromise = this.apiService.setPassword(request).then(async () => { - await this.onSetPasswordSuccess(key, encKey, keys); + await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair); }); } @@ -172,19 +175,19 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { } private async onSetPasswordSuccess( - key: SymmetricCryptoKey, - encKey: [SymmetricCryptoKey, EncString], - keys: [string, EncString] + masterKey: MasterKey, + userKey: [UserSymKey, EncString], + keyPair: [string, EncString] ) { await this.stateService.setKdfType(this.kdf); await this.stateService.setKdfConfig(this.kdfConfig); - await this.cryptoService.setKey(key); - await this.cryptoService.setEncKey(encKey[1].encryptedString); - await this.cryptoService.setEncPrivateKey(keys[1].encryptedString); + await this.cryptoService.setMasterKey(masterKey); + await this.cryptoService.setUserKey(userKey[0]); + await this.cryptoService.setPrivateKey(keyPair[1].encryptedString); const localKeyHash = await this.cryptoService.hashPassword( this.masterPassword, - key, + masterKey, HashPurpose.LocalAuthorization ); await this.cryptoService.setKeyHash(localKeyHash); diff --git a/libs/common/src/platform/abstractions/crypto.service.ts b/libs/common/src/platform/abstractions/crypto.service.ts index 34545484f18..c71d53b1f7f 100644 --- a/libs/common/src/platform/abstractions/crypto.service.ts +++ b/libs/common/src/platform/abstractions/crypto.service.ts @@ -33,7 +33,7 @@ export abstract class CryptoService { keySuffix?: KeySuffixOptions.Auto | KeySuffixOptions.Biometric, userId?: string ) => Promise; - makeUserSymKey: (key: SymmetricCryptoKey) => Promise<[UserSymKey, EncString]>; + makeUserSymKey: (key: MasterKey) => Promise<[UserSymKey, EncString]>; clearUserKey: (clearSecretStorage?: boolean, userId?: string) => Promise; setUserSymKeyMasterKey: (UserSymKeyMasterKey: string, userId?: string) => Promise; setMasterKey: (key: MasterKey, userId?: string) => Promise;