mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
[PM-21033/PM-22863] User Encryption v2 (#14942)
* Add new encrypt service functions * Undo changes * Cleanup * Fix build * Fix comments * Switch encrypt service to use SDK functions * Move remaining functions to PureCrypto * Tests * Increase test coverage * Split up userkey rotation v2 and add tests * Fix eslint * Fix type errors * Fix tests * Implement signing keys * Fix sdk init * Remove key rotation v2 flag * Fix parsing when user does not have signing keys * Clear up trusted key naming * Split up getNewAccountKeys * Add trim and lowercase * Replace user.email with masterKeySalt * Add wasTrustDenied to verifyTrust in key rotation service * Move testable userkey rotation service code to testable class * Fix build * Add comments * Undo changes * Fix incorrect behavior on aborting key rotation and fix import * Fix tests * Make members of userkey rotation service protected * Fix type error * Cleanup and add injectable annotation * Fix tests * Update apps/web/src/app/key-management/key-rotation/user-key-rotation.service.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove v1 rotation request * Add upgrade to user encryption v2 * Fix types * Update sdk method calls * Update request models for new server api for rotation * Fix build * Update userkey rotation for new server API * Update crypto client call for new sdk changes * Fix rotation with signing keys * Cargo lock * Fix userkey rotation service * Fix types * Undo changes to feature flag service * Fix linting * [PM-22863] Account security state (#15309) * Add account security state * Update key rotation * Rename * Fix build * Cleanup * Further cleanup * Tests * Increase test coverage * Add test * Increase test coverage * Fix builds and update sdk * Fix build * Fix tests * Reset changes to encrypt service * Cleanup * Add comment * Cleanup * Cleanup * Rename model * Cleanup * Fix build * Clean up * Fix types * Cleanup * Cleanup * Cleanup * Add test * Simplify request model * Rename and add comments * Fix tests * Update responses to use less strict typing * Fix response parsing for v1 users * Update libs/common/src/key-management/keys/response/private-keys.response.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update libs/common/src/key-management/keys/response/private-keys.response.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix build * Fix build * Fix build * Undo change * Fix attachments not encrypting for v2 users --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
} from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
||||
import { WrappedSigningKey } from "@bitwarden/common/key-management/types";
|
||||
import { VaultTimeoutStringType } from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { VAULT_TIMEOUT } from "@bitwarden/common/key-management/vault-timeout/services/vault-timeout-settings.state";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -44,6 +45,7 @@ import {
|
||||
USER_ENCRYPTED_PRIVATE_KEY,
|
||||
USER_EVER_HAD_USER_KEY,
|
||||
USER_KEY,
|
||||
USER_KEY_ENCRYPTED_SIGNING_KEY,
|
||||
} from "@bitwarden/common/platform/services/key-state/user-key.state";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
@@ -398,8 +400,10 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
throw new Error("No key provided");
|
||||
}
|
||||
|
||||
const newSymKey = await this.keyGenerationService.createKey(512);
|
||||
return this.buildProtectedSymmetricKey(key, newSymKey);
|
||||
// Content encryption key is AES256_CBC_HMAC
|
||||
const cek = await this.keyGenerationService.createKey(512);
|
||||
const wrappedCek = await this.encryptService.wrapSymmetricKey(cek, key);
|
||||
return [cek, wrappedCek];
|
||||
}
|
||||
|
||||
private async clearOrgKeys(userId: UserId): Promise<void> {
|
||||
@@ -505,6 +509,10 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
await this.stateProvider.setUserState(USER_ENCRYPTED_PRIVATE_KEY, null, userId);
|
||||
}
|
||||
|
||||
private async clearSigningKey(userId: UserId): Promise<void> {
|
||||
await this.stateProvider.setUserState(USER_KEY_ENCRYPTED_SIGNING_KEY, null, userId);
|
||||
}
|
||||
|
||||
async clearPinKeys(userId: UserId): Promise<void> {
|
||||
if (userId == null) {
|
||||
throw new Error("UserId is required");
|
||||
@@ -537,6 +545,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
await this.clearOrgKeys(userId);
|
||||
await this.clearProviderKeys(userId);
|
||||
await this.clearKeyPair(userId);
|
||||
await this.clearSigningKey(userId);
|
||||
await this.clearPinKeys(userId);
|
||||
await this.stateProvider.setUserState(USER_EVER_HAD_USER_KEY, null, userId);
|
||||
}
|
||||
@@ -758,6 +767,10 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
return phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* This should only be used for wrapping the user key with a master key or stretched master key.
|
||||
*/
|
||||
private async buildProtectedSymmetricKey<T extends SymmetricCryptoKey>(
|
||||
encryptionKey: SymmetricCryptoKey,
|
||||
newSymKey: SymmetricCryptoKey,
|
||||
@@ -792,7 +805,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (await this.cryptoFunctionService.rsaExtractPublicKey(privateKey)) as UserPublicKey;
|
||||
return await this.cryptoFunctionService.rsaExtractPublicKey(privateKey);
|
||||
}
|
||||
|
||||
userPrivateKey$(userId: UserId): Observable<UserPrivateKey | null> {
|
||||
@@ -808,7 +821,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
return null;
|
||||
}
|
||||
|
||||
const publicKey = (await this.derivePublicKey(privateKey))!;
|
||||
const publicKey = (await this.derivePublicKey(privateKey))! as UserPublicKey;
|
||||
return { privateKey, publicKey };
|
||||
}),
|
||||
);
|
||||
@@ -905,6 +918,27 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
);
|
||||
}
|
||||
|
||||
async setUserSigningKey(userSigningKey: WrappedSigningKey, userId: UserId): Promise<void> {
|
||||
if (userSigningKey == null) {
|
||||
throw new Error("No user signing key provided.");
|
||||
}
|
||||
if (userId == null) {
|
||||
throw new Error("No userId provided.");
|
||||
}
|
||||
await this.stateProvider.setUserState(USER_KEY_ENCRYPTED_SIGNING_KEY, userSigningKey, userId);
|
||||
}
|
||||
|
||||
userSigningKey$(userId: UserId): Observable<WrappedSigningKey | null> {
|
||||
return this.stateProvider.getUser(userId, USER_KEY_ENCRYPTED_SIGNING_KEY).state$.pipe(
|
||||
map((encryptedSigningKey) => {
|
||||
if (encryptedSigningKey == null) {
|
||||
return null;
|
||||
}
|
||||
return encryptedSigningKey as WrappedSigningKey;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
orgKeys$(userId: UserId): Observable<Record<OrganizationId, OrgKey> | null> {
|
||||
return this.cipherDecryptionKeys$(userId).pipe(map((keys) => keys?.orgKeys ?? null));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user