1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-29 12:55:21 +01:00

rename 'user symmetric key' with 'user key'

This commit is contained in:
Jacob Fink 2023-06-23 10:59:54 -04:00
parent e4bfa62e70
commit 6349410ec2
No known key found for this signature in database
GPG Key ID: C2F7ACF05859D008
47 changed files with 423 additions and 457 deletions

View File

@ -13,7 +13,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { BrowserApi } from "../platform/browser/browser-api";
@ -329,19 +329,19 @@ export class NativeMessagingBackground {
if (message.userKeyB64) {
const userKey = new SymmetricCryptoKey(
Utils.fromB64ToArray(message.userKeyB64).buffer
) as UserSymKey;
) as UserKey;
await this.cryptoService.setUserKey(userKey);
} else if (message.keyB64) {
// backwards compatibility
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
encUserKey ||= await this.stateService.getUserSymKeyMasterKey();
encUserKey ||= await this.stateService.getUserKeyMasterKey();
if (!encUserKey) {
throw new Error("No encrypted user key found");
}
const masterKey = new SymmetricCryptoKey(
Utils.fromB64ToArray(message.keyB64).buffer
) as MasterKey;
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
masterKey,
new EncString(encUserKey)
);

View File

@ -2,7 +2,7 @@ import { KeySuffixOptions } from "@bitwarden/common/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import {
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
@ -10,12 +10,12 @@ export class BrowserCryptoService extends CryptoService {
protected override async retrieveUserKeyFromStorage(
keySuffix: KeySuffixOptions,
userId?: string
): Promise<UserSymKey> {
): Promise<UserKey> {
if (keySuffix === KeySuffixOptions.Biometric) {
await this.platformUtilService.authenticateBiometric();
const userKey = await this.getUserKeyFromMemory();
if (userKey) {
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey.keyB64).buffer) as UserSymKey;
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey.keyB64).buffer) as UserKey;
}
}

View File

@ -408,7 +408,7 @@ export class LoginCommand {
try {
const {
newPasswordHash,
newUserSymKey: newEncKey,
newUserKey: newEncKey,
hint,
} = await this.collectNewMasterPasswordDetails(
"Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now."
@ -450,7 +450,7 @@ export class LoginCommand {
try {
const {
newPasswordHash,
newUserSymKey: newEncKey,
newUserKey: newEncKey,
hint,
} = await this.collectNewMasterPasswordDetails(
"An organization administrator recently changed your master password. In order to access the vault, you must update your master password now."
@ -476,7 +476,7 @@ export class LoginCommand {
/**
* Collect new master password and hint from the CLI. The collected password
* is validated against any applicable master password policies, a new master
* key is generated, and we use it to re-encrypt the user symmetric key
* key is generated, and we use it to re-encrypt the user key
* @param prompt - Message that is displayed during the initial prompt
* @param error
*/
@ -485,7 +485,7 @@ export class LoginCommand {
error?: string
): Promise<{
newPasswordHash: string;
newUserSymKey: [SymmetricCryptoKey, EncString];
newUserKey: [SymmetricCryptoKey, EncString];
hint?: string;
}> {
if (this.email == null || this.email === "undefined") {
@ -575,19 +575,16 @@ export class LoginCommand {
);
const newPasswordHash = await this.cryptoService.hashPassword(masterPassword, newMasterKey);
// Grab user's symmetric key
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
if (!userSymKey) {
// Grab user key
const userKey = await this.cryptoService.getUserKeyFromMemory();
if (!userKey) {
throw new Error("User key not found.");
}
// Re-encrypt user's symmetric key with new master key
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
newMasterKey,
userSymKey
);
// Re-encrypt user key with new master key
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey, userKey);
return { newPasswordHash, newUserSymKey, hint: masterPasswordHint };
return { newPasswordHash, newUserKey: newUserKey, hint: masterPasswordHint };
}
private async handleCaptchaRequired(

View File

@ -76,7 +76,7 @@ export class UnlockCommand {
if (passwordValid) {
await this.cryptoService.setMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setUserKey(userKey);
if (await this.keyConnectorService.getConvertAccountRequired()) {

View File

@ -126,8 +126,8 @@ export class CreateCommand {
return Response.error("Premium status is required to use this feature.");
}
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
if (userSymKey == null) {
const userKey = await this.cryptoService.getUserKeyFromMemory();
if (userKey == null) {
return Response.error(
"You must update your encryption key before you can use this feature. " +
"See https://help.bitwarden.com/article/update-encryption-key/"

View File

@ -8,7 +8,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
import { CsprngString } from "@bitwarden/common/types/csprng";
@ -26,7 +26,7 @@ export class ElectronCryptoService extends CryptoService {
super(cryptoFunctionService, encryptService, platformUtilsService, logService, stateService);
}
protected override async storeAdditionalKeys(key: UserSymKey, userId?: string) {
protected override async storeAdditionalKeys(key: UserKey, userId?: string) {
await super.storeAdditionalKeys(key, userId);
const storeBiometricKey = await this.shouldStoreKey(KeySuffixOptions.Biometric, userId);
@ -34,28 +34,28 @@ export class ElectronCryptoService extends CryptoService {
if (storeBiometricKey) {
await this.storeBiometricKey(key, userId);
} else {
await this.stateService.setUserSymKeyBiometric(null, { userId: userId });
await this.stateService.setUserKeyBiometric(null, { userId: userId });
}
}
protected override async retrieveUserKeyFromStorage(
keySuffix: KeySuffixOptions,
userId?: string
): Promise<UserSymKey> {
): Promise<UserKey> {
if (keySuffix === KeySuffixOptions.Biometric) {
await this.migrateBiometricKeyIfNeeded(userId);
const userKey = await this.stateService.getUserSymKeyBiometric({ userId: userId });
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserSymKey;
const userKey = await this.stateService.getUserKeyBiometric({ userId: userId });
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserKey;
}
return await super.retrieveUserKeyFromStorage(keySuffix, userId);
}
protected async storeBiometricKey(key: UserSymKey, userId?: string): Promise<void> {
protected async storeBiometricKey(key: UserKey, userId?: string): Promise<void> {
let clientEncKeyHalf: CsprngString = null;
if (await this.stateService.getBiometricRequirePasswordOnStart({ userId })) {
clientEncKeyHalf = await this.getBiometricEncryptionClientKeyHalf(userId);
}
await this.stateService.setUserSymKeyBiometric(
await this.stateService.setUserKeyBiometric(
{ key: key.keyB64, clientEncKeyHalf },
{ userId: userId }
);
@ -87,16 +87,13 @@ export class ElectronCryptoService extends CryptoService {
// decrypt
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
encUserKey = encUserKey ?? (await this.stateService.getUserSymKeyMasterKey());
encUserKey = encUserKey ?? (await this.stateService.getUserKeyMasterKey());
if (!encUserKey) {
throw new Error("No user key found during biometric migration");
}
const userSymKey = await this.decryptUserSymKeyWithMasterKey(
masterKey,
new EncString(encUserKey)
);
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, new EncString(encUserKey));
// migrate
await this.storeBiometricKey(userSymKey, userId);
await this.storeBiometricKey(userKey, userId);
await this.stateService.setCryptoMasterKeyBiometric(null, { userId });
}
}

View File

@ -25,7 +25,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
@ -176,7 +176,7 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
// Decrypt User's Reset Password Key to get EncKey
const decValue = await this.cryptoService.rsaDecrypt(resetPasswordKey, decPrivateKey);
const existingUserSymKey = new SymmetricCryptoKey(decValue) as UserSymKey;
const existingUserKey = new SymmetricCryptoKey(decValue) as UserKey;
// Create new master key and hash new password
const newMasterKey = await this.cryptoService.makeMasterKey(
@ -190,15 +190,15 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
newMasterKey
);
// Create new encrypted user symmetric key for the User
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
// Create new encrypted user key for the User
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(
newMasterKey,
existingUserSymKey
existingUserKey
);
// Create request
const request = new OrganizationUserResetPasswordRequest();
request.key = newUserSymKey[1].encryptedString;
request.key = newUserKey[1].encryptedString;
request.newMasterPasswordHash = newPasswordHash;
// Change user's password

View File

@ -19,7 +19,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import {
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
@ -94,9 +94,9 @@ export class EmergencyAccessTakeoverComponent
);
const oldKeyBuffer = await this.cryptoService.rsaDecrypt(takeoverResponse.keyEncrypted);
const oldUserSymKey = new SymmetricCryptoKey(oldKeyBuffer) as UserSymKey;
const oldUserKey = new SymmetricCryptoKey(oldKeyBuffer) as UserKey;
if (oldUserSymKey == null) {
if (oldUserKey == null) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
@ -120,10 +120,7 @@ export class EmergencyAccessTakeoverComponent
masterKey
);
const encKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
masterKey,
oldUserSymKey
);
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, oldUserKey);
const request = new EmergencyAccessPasswordRequest();
request.newMasterPasswordHash = masterPasswordHash;

View File

@ -77,8 +77,8 @@ export class ChangeEmailComponent implements OnInit {
this.masterPassword,
newMasterKey
);
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(newMasterKey);
request.key = newUserSymKey[1].encryptedString;
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
request.key = newUserKey[1].encryptedString;
try {
this.formPromise = this.apiService.postEmail(request);
await this.formPromise;

View File

@ -87,8 +87,8 @@ export class ChangeKdfConfirmationComponent {
masterPassword,
newMasterKey
);
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(newMasterKey);
request.key = newUserSymKey[1].encryptedString;
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
request.key = newUserKey[1].encryptedString;
await this.apiService.postAccountKdf(request);
}

View File

@ -26,7 +26,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} 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";
@ -184,7 +184,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
async performSubmitActions(
newMasterPasswordHash: string,
newMasterKey: MasterKey,
newUserKey: [UserSymKey, EncString]
newUserKey: [UserKey, EncString]
) {
const request = new PasswordRequest();
request.masterPasswordHash = await this.cryptoService.hashPassword(
@ -218,15 +218,15 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
}
private async updateKey(masterKey: MasterKey, masterPasswordHash: string) {
const userSymKey = await this.cryptoService.makeUserSymKey(masterKey);
const userKey = await this.cryptoService.makeUserKey(masterKey);
const privateKey = await this.cryptoService.getPrivateKey();
let encPrivateKey: EncString = null;
if (privateKey != null) {
encPrivateKey = await this.cryptoService.encrypt(privateKey, userSymKey[0]);
encPrivateKey = await this.cryptoService.encrypt(privateKey, userKey[0]);
}
const request = new UpdateKeyRequest();
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
request.key = userSymKey[1].encryptedString;
request.key = userKey[1].encryptedString;
request.masterPasswordHash = masterPasswordHash;
const folders = await firstValueFrom(this.folderService.folderViews$);
@ -234,7 +234,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
if (folders[i].id == null) {
continue;
}
const folder = await this.folderService.encrypt(folders[i], userSymKey[0]);
const folder = await this.folderService.encrypt(folders[i], userKey[0]);
request.folders.push(new FolderWithIdRequest(folder));
}
@ -244,7 +244,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
continue;
}
const cipher = await this.cipherService.encrypt(ciphers[i], userSymKey[0]);
const cipher = await this.cipherService.encrypt(ciphers[i], userKey[0]);
request.ciphers.push(new CipherWithIdRequest(cipher));
}
@ -252,16 +252,16 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
await Promise.all(
sends.map(async (send) => {
const sendKey = await this.cryptoService.decryptToBytes(send.key, null);
send.key = (await this.cryptoService.encrypt(sendKey, userSymKey[0])) ?? send.key;
send.key = (await this.cryptoService.encrypt(sendKey, userKey[0])) ?? send.key;
request.sends.push(new SendWithIdRequest(send));
})
);
await this.apiService.postAccountKey(request);
await this.updateEmergencyAccesses(userSymKey[0]);
await this.updateEmergencyAccesses(userKey[0]);
await this.updateAllResetPasswordKeys(userSymKey[0], masterPasswordHash);
await this.updateAllResetPasswordKeys(userKey[0], masterPasswordHash);
}
private async updateEmergencyAccesses(encKey: SymmetricCryptoKey) {
@ -289,7 +289,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
}
}
private async updateAllResetPasswordKeys(userSymKey: UserSymKey, masterPasswordHash: string) {
private async updateAllResetPasswordKeys(userKey: UserKey, masterPasswordHash: string) {
const orgs = await this.organizationService.getAll();
for (const org of orgs) {
@ -303,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(userSymKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(userKey.key, publicKey.buffer);
// Create/Execute request
const request = new OrganizationUserResetPasswordEnrollmentRequest();

View File

@ -69,7 +69,7 @@ export class UpdateKeyComponent {
private async makeRequest(): Promise<UpdateKeyRequest> {
const masterKey = await this.cryptoService.getMasterKey();
const newUserKey = await this.cryptoService.makeUserSymKey(masterKey);
const newUserKey = await this.cryptoService.makeUserKey(masterKey);
const privateKey = await this.cryptoService.getPrivateKey();
let encPrivateKey: EncString = null;
if (privateKey != null) {

View File

@ -2,7 +2,7 @@ export class AdminAuthRequestUpdateRequest {
/**
*
* @param requestApproved - Whether the request was approved/denied. If true, the key must be provided.
* @param encryptedUserKey The user's symmetric key that has been encrypted with a device public key if the request was approved.
* @param encryptedUserKey The user key that has been encrypted with a device public key if the request was approved.
*/
constructor(public requestApproved: boolean, public encryptedUserKey?: string) {}
}

View File

@ -65,16 +65,16 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
}
/**
* Creates a copy of the user's symmetric key that has been encrypted with the provided device's public key.
* Creates a copy of the user key that has been encrypted with the provided device's public key.
* @param devicePublicKey
* @param resetPasswordDetails
* @private
*/
private async getEncryptedUserSymKey(
private async getEncryptedUserKey(
devicePublicKey: string,
resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse
): Promise<EncString> {
const encryptedUserSymKey = resetPasswordDetails.resetPasswordKey;
const encryptedUserKey = resetPasswordDetails.resetPasswordKey;
const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey;
const devicePubKey = Utils.fromB64ToArray(devicePublicKey);
@ -85,12 +85,12 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
orgSymKey
);
// Decrypt User's symmetric key with decrypted org private key
const decValue = await this.cryptoService.rsaDecrypt(encryptedUserSymKey, decOrgPrivateKey);
const userSymKey = new SymmetricCryptoKey(decValue);
// Decrypt user key with decrypted org private key
const decValue = await this.cryptoService.rsaDecrypt(encryptedUserKey, decOrgPrivateKey);
const userKey = new SymmetricCryptoKey(decValue);
// Re-encrypt User's Symmetric Key with the Device Public Key
return await this.cryptoService.rsaEncrypt(userSymKey.key, devicePubKey.buffer);
// Re-encrypt user Key with the Device Public Key
return await this.cryptoService.rsaEncrypt(userKey.key, devicePubKey.buffer);
}
async approveRequest(authRequest: PendingAuthRequestView) {
@ -110,7 +110,7 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
return;
}
const encryptedKey = await this.getEncryptedUserSymKey(authRequest.publicKey, details);
const encryptedKey = await this.getEncryptedUserKey(authRequest.publicKey, details);
await this.organizationAuthRequestService.approvePendingRequest(
this.organizationId,

View File

@ -12,10 +12,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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
MasterKey,
UserSymKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
@ -95,17 +92,15 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
newMasterKey
);
let newProtectedUserSymKey: [UserSymKey, EncString] = null;
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
if (userSymKey == null) {
newProtectedUserSymKey = await this.cryptoService.makeUserSymKey(newMasterKey);
let newProtectedUserKey: [UserKey, EncString] = null;
const userKey = await this.cryptoService.getUserKeyFromMemory();
if (userKey == null) {
newProtectedUserKey = await this.cryptoService.makeUserKey(newMasterKey);
} else {
newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
newMasterKey
);
newProtectedUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
}
await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserSymKey);
await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserKey);
}
async setupSubmitActions(): Promise<boolean> {
@ -117,7 +112,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
async performSubmitActions(
masterPasswordHash: string,
masterKey: MasterKey,
userSymKey: [UserSymKey, EncString]
userKey: [UserKey, EncString]
) {
// Override in sub-class
}

View File

@ -24,7 +24,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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { UserSymKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
@ -153,41 +153,41 @@ export class LockComponent implements OnInit, OnDestroy {
try {
const kdf = await this.stateService.getKdfType();
const kdfConfig = await this.stateService.getKdfConfig();
let userSymKeyPin: EncString;
let userKeyPin: EncString;
let oldPinProtected: EncString;
if (this.pinSet[0]) {
// MP on restart enabled
userSymKeyPin = await this.stateService.getUserSymKeyPinEphemeral();
userKeyPin = await this.stateService.getUserKeyPinEphemeral();
oldPinProtected = await this.stateService.getDecryptedPinProtected();
} else {
// MP on restart disabled
userSymKeyPin = await this.stateService.getUserSymKeyPin();
userKeyPin = await this.stateService.getUserKeyPin();
const oldEncryptedKey = await this.stateService.getEncryptedPinProtected();
oldPinProtected = oldEncryptedKey ? new EncString(oldEncryptedKey) : undefined;
}
let userSymKey: UserSymKey;
let userKey: UserKey;
if (oldPinProtected) {
userSymKey = await this.decryptAndMigrateOldPinKey(true, kdf, kdfConfig, oldPinProtected);
userKey = await this.decryptAndMigrateOldPinKey(true, kdf, kdfConfig, oldPinProtected);
} else {
userSymKey = await this.cryptoService.decryptUserSymKeyWithPin(
userKey = await this.cryptoService.decryptUserKeyWithPin(
this.pin,
this.email,
kdf,
kdfConfig,
userSymKeyPin
userKeyPin
);
}
const protectedPin = await this.stateService.getProtectedPin();
const decryptedPin = await this.cryptoService.decryptToUtf8(
new EncString(protectedPin),
userSymKey
userKey
);
failed = decryptedPin !== this.pin;
if (!failed) {
await this.setKeyAndContinue(userSymKey);
await this.setKeyAndContinue(userKey);
}
} catch {
failed = true;
@ -275,22 +275,22 @@ export class LockComponent implements OnInit, OnDestroy {
return;
}
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
// if MP on restart is enabled, use it to get the PIN and store the ephemeral
// pin protected user symmetric key
// pin protected user key
if (this.pinSet[0]) {
const protectedPin = await this.stateService.getProtectedPin();
const pin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), userKey);
const pinKey = await this.cryptoService.makePinKey(pin, this.email, kdf, kdfConfig);
await this.stateService.setUserSymKeyPinEphemeral(
await this.stateService.setUserKeyPinEphemeral(
await this.cryptoService.encrypt(userKey.key, pinKey)
);
}
await this.setKeyAndContinue(userKey, true);
}
private async setKeyAndContinue(key: UserSymKey, evaluatePasswordAfterUnlock = false) {
private async setKeyAndContinue(key: UserKey, evaluatePasswordAfterUnlock = false) {
await this.cryptoService.setUserKey(key);
await this.doContinue(evaluatePasswordAfterUnlock);
}
@ -331,7 +331,7 @@ export class LockComponent implements OnInit, OnDestroy {
private async load() {
this.pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
let ephemeralPinSet = await this.stateService.getUserSymKeyPinEphemeral();
let ephemeralPinSet = await this.stateService.getUserKeyPinEphemeral();
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
this.pinLock = (this.pinSet[0] && !!ephemeralPinSet) || this.pinSet[1];
@ -381,21 +381,21 @@ export class LockComponent implements OnInit, OnDestroy {
}
/**
* Creates a new Pin key that encrypts the user's symmetric key instead of the
* Creates a new Pin key that encrypts the user key instead of the
* master key. Clears the old Pin key from state.
* @param masterPasswordOnRestart True if Master Password on Restart is enabled
* @param kdf User's KdfType
* @param kdfConfig User's KdfConfig
* @param oldPinProtected The old Pin key from state (retrieved from different
* places depending on if Master Password on Restart was enabled)
* @returns The user's symmetric key
* @returns The user key
*/
private async decryptAndMigrateOldPinKey(
masterPasswordOnRestart: boolean,
kdf: KdfType,
kdfConfig: KdfConfig,
oldPinProtected?: EncString
): Promise<UserSymKey> {
): Promise<UserKey> {
// Decrypt
const masterKey = await this.cryptoService.decryptMasterKeyWithPin(
this.pin,
@ -404,28 +404,28 @@ export class LockComponent implements OnInit, OnDestroy {
kdfConfig,
oldPinProtected
);
const encUserSymKey = await this.stateService.getEncryptedCryptoSymmetricKey();
const userSymKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(
const encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
masterKey,
new EncString(encUserSymKey)
new EncString(encUserKey)
);
// Migrate
const pinKey = await this.cryptoService.makePinKey(this.pin, this.email, kdf, kdfConfig);
const pinProtectedKey = await this.cryptoService.encrypt(userSymKey.key, pinKey);
const pinProtectedKey = await this.cryptoService.encrypt(userKey.key, pinKey);
if (masterPasswordOnRestart) {
await this.stateService.setDecryptedPinProtected(null);
await this.stateService.setUserSymKeyPinEphemeral(pinProtectedKey);
await this.stateService.setUserKeyPinEphemeral(pinProtectedKey);
} else {
await this.stateService.setEncryptedPinProtected(null);
await this.stateService.setUserSymKeyPin(pinProtectedKey);
await this.stateService.setUserKeyPin(pinProtectedKey);
// We previously only set the protected pin if MP on Restart was enabled
// now we set it regardless
const encPin = await this.cryptoService.encrypt(this.pin, userSymKey);
const encPin = await this.cryptoService.encrypt(this.pin, userKey);
await this.stateService.setProtectedPin(encPin.encryptedString);
}
// This also clears the old Biometrics key since the new Biometrics key will
// be created when the user's symmetric key is set.
// be created when the user key is set.
await this.stateService.setCryptoMasterKeyBiometric(null);
return userSymKey;
return userKey;
}
}

View File

@ -14,10 +14,7 @@ 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 {
MasterKey,
UserSymKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { Verification } from "@bitwarden/common/types/verification";
@ -100,7 +97,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
async performSubmitActions(
masterPasswordHash: string,
masterKey: MasterKey,
userSymKey: [UserSymKey, EncString]
userKey: [UserKey, EncString]
) {
try {
// Create Request
@ -110,7 +107,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
null
);
request.newMasterPasswordHash = masterPasswordHash;
request.key = userSymKey[1].encryptedString;
request.key = userKey[1].encryptedString;
// Update user's password
this.apiService.postPassword(request);

View File

@ -16,10 +16,7 @@ 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 {
MasterKey,
UserSymKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { MasterKey, UserKey } 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";
@ -128,16 +125,16 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
newMasterKey
);
// Grab user's symmetric key
// Grab user key
const userKey = await this.cryptoService.getUserKeyFromMemory();
// Encrypt user's symmetric key with new master key
const newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
// Encrypt user key with new master key
const newProtectedUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(
newMasterKey,
userKey
);
await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserSymKey);
await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserKey);
} catch (e) {
this.logService.error(e);
}
@ -146,15 +143,15 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
async performSubmitActions(
masterPasswordHash: string,
masterKey: MasterKey,
userSymKey: [UserSymKey, EncString]
userKey: [UserKey, EncString]
) {
try {
switch (this.reason) {
case ForceResetPasswordReason.AdminForcePasswordReset:
this.formPromise = this.updateTempPassword(masterPasswordHash, userSymKey);
this.formPromise = this.updateTempPassword(masterPasswordHash, userKey);
break;
case ForceResetPasswordReason.WeakMasterPassword:
this.formPromise = this.updatePassword(masterPasswordHash, userSymKey);
this.formPromise = this.updatePassword(masterPasswordHash, userKey);
break;
}
@ -176,26 +173,23 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
this.logService.error(e);
}
}
private async updateTempPassword(
masterPasswordHash: string,
userSymKey: [UserSymKey, EncString]
) {
private async updateTempPassword(masterPasswordHash: string, userKey: [UserKey, EncString]) {
const request = new UpdateTempPasswordRequest();
request.key = userSymKey[1].encryptedString;
request.key = userKey[1].encryptedString;
request.newMasterPasswordHash = masterPasswordHash;
request.masterPasswordHint = this.hint;
return this.apiService.putUpdateTempPassword(request);
}
private async updatePassword(newMasterPasswordHash: string, userSymKey: [UserSymKey, EncString]) {
private async updatePassword(newMasterPasswordHash: string, userKey: [UserKey, EncString]) {
const request = await this.userVerificationService.buildRequest(
this.verification,
PasswordRequest
);
request.masterPasswordHint = this.hint;
request.newMasterPasswordHash = newMasterPasswordHash;
request.key = userSymKey[1].encryptedString;
request.key = userKey[1].encryptedString;
return this.apiService.postPassword(request);
}

View File

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

View File

@ -18,10 +18,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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import {
MasterKey,
UserSymKey,
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { MasterKey, UserKey } 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";
@ -105,7 +102,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
async performSubmitActions(
masterPasswordHash: string,
masterKey: MasterKey,
userKey: [UserSymKey, EncString]
userKey: [UserKey, EncString]
) {
const newKeyPair = await this.cryptoService.makeKeyPair(userKey[0]);
const request = new SetPasswordRequest(
@ -134,7 +131,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
const userId = await this.stateService.getUserId();
const publicKey = Utils.fromB64ToArray(response.publicKey);
// RSA Encrypt user's symmetric key with organization public key
// RSA Encrypt user key with organization public key
const userKey = await this.cryptoService.getUserKeyFromMemory();
const encryptedUserKey = await this.cryptoService.rsaEncrypt(
userKey.key,
@ -176,7 +173,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
private async onSetPasswordSuccess(
masterKey: MasterKey,
userKey: [UserSymKey, EncString],
userKey: [UserKey, EncString],
keyPair: [string, EncString]
) {
await this.stateService.setKdfType(this.kdf);

View File

@ -46,9 +46,9 @@ export class SetPinComponent implements OnInit {
const encPin = await this.cryptoService.encrypt(this.pin, userKey);
await this.stateService.setProtectedPin(encPin.encryptedString);
if (this.masterPassOnRestart) {
await this.stateService.setUserSymKeyPinEphemeral(pinProtectedKey);
await this.stateService.setUserKeyPinEphemeral(pinProtectedKey);
} else {
await this.stateService.setUserSymKeyPin(pinProtectedKey);
await this.stateService.setUserKeyPin(pinProtectedKey);
}
await this.cryptoService.clearOldPinKeys();

View File

@ -7,8 +7,8 @@ export abstract class DevicesApiServiceAbstraction {
updateTrustedDeviceKeys: (
deviceIdentifier: string,
devicePublicKeyEncryptedUserSymKey: string,
userSymKeyEncryptedDevicePublicKey: string,
devicePublicKeyEncryptedUserKey: string,
userKeyEncryptedDevicePublicKey: string,
deviceKeyEncryptedDevicePrivateKey: string
) => Promise<DeviceResponse>;
}

View File

@ -14,7 +14,7 @@ import { EncString } from "../../platform/models/domain/enc-string";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../../platform/models/domain/symmetric-crypto-key";
import {
PasswordStrengthService,
@ -43,7 +43,7 @@ const masterPassword = "password";
const deviceId = Utils.newGuid();
const accessToken = "ACCESS_TOKEN";
const refreshToken = "REFRESH_TOKEN";
const userSymKey = "USER_SYM_KEY";
const userKey = "USER_KEY";
const privateKey = "PRIVATE_KEY";
const captchaSiteKey = "CAPTCHA_SITE_KEY";
const kdf = 0;
@ -70,7 +70,7 @@ export function identityTokenResponseFactory(
ForcePasswordReset: false,
Kdf: kdf,
KdfIterations: kdfIterations,
Key: userSymKey,
Key: userKey,
PrivateKey: privateKey,
ResetMasterPassword: false,
access_token: accessToken,
@ -135,15 +135,15 @@ describe("LogInStrategy", () => {
});
describe("base class", () => {
const userSymKeyBytesLength = 64;
const userKeyBytesLength = 64;
const masterKeyBytesLength = 64;
let userSymKey: UserSymKey;
let userKey: UserKey;
let masterKey: MasterKey;
beforeEach(() => {
userSymKey = new SymmetricCryptoKey(
new Uint8Array(userSymKeyBytesLength).buffer as CsprngArray
) as UserSymKey;
userKey = new SymmetricCryptoKey(
new Uint8Array(userKeyBytesLength).buffer as CsprngArray
) as UserKey;
masterKey = new SymmetricCryptoKey(
new Uint8Array(masterKeyBytesLength).buffer as CsprngArray
) as MasterKey;
@ -206,7 +206,7 @@ describe("LogInStrategy", () => {
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
const result = await passwordLogInStrategy.logIn(credentials);
@ -225,7 +225,7 @@ describe("LogInStrategy", () => {
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
await passwordLogInStrategy.logIn(credentials);

View File

@ -13,7 +13,7 @@ import { Utils } from "../../platform/misc/utils";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../../platform/models/domain/symmetric-crypto-key";
import {
PasswordStrengthService,
@ -134,19 +134,17 @@ describe("PasswordLogInStrategy", () => {
});
it("sets keys after a successful authentication", async () => {
const userSymKey = new SymmetricCryptoKey(
new Uint8Array(64).buffer as CsprngArray
) as UserSymKey;
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
await passwordLogInStrategy.logIn(credentials);
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localHashedPassword);
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
});

View File

@ -147,11 +147,11 @@ export class PasswordLogInStrategy extends LogInStrategy {
}
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
await this.cryptoService.setUserSymKeyMasterKey(response.key);
await this.cryptoService.setUserKeyMasterKey(response.key);
const masterKey = await this.cryptoService.getMasterKey();
if (masterKey) {
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setUserKey(userKey);
}
}

View File

@ -11,7 +11,7 @@ import { Utils } from "../../platform/misc/utils";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../../platform/models/domain/symmetric-crypto-key";
import { CsprngArray } from "../../types/csprng";
import { TokenService } from "../abstractions/token.service";
@ -85,19 +85,17 @@ describe("SsoLogInStrategy", () => {
it("sets keys after a successful authentication", async () => {
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
const userSymKey = new SymmetricCryptoKey(
new Uint8Array(64).buffer as CsprngArray
) as UserSymKey;
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
await passwordlessLoginStrategy.logIn(credentials);
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localPasswordHash);
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
});
});

View File

@ -85,11 +85,11 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
}
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
await this.cryptoService.setUserSymKeyMasterKey(response.key);
await this.cryptoService.setUserKeyMasterKey(response.key);
const masterKey = await this.cryptoService.getMasterKey();
if (masterKey) {
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setUserKey(userKey);
}
}

View File

@ -11,7 +11,7 @@ import { Utils } from "../../platform/misc/utils";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../../platform/models/domain/symmetric-crypto-key";
import { CsprngArray } from "../../types/csprng";
import { KeyConnectorService } from "../abstractions/key-connector.service";
@ -143,22 +143,20 @@ describe("SsoLogInStrategy", () => {
);
});
it("decrypts and sets the user symmetric key if Key Connector is enabled", async () => {
const userSymKey = new SymmetricCryptoKey(
new Uint8Array(64).buffer as CsprngArray
) as UserSymKey;
it("decrypts and sets the user key if Key Connector is enabled", async () => {
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
const masterKey = new SymmetricCryptoKey(
new Uint8Array(64).buffer as CsprngArray
) as MasterKey;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
await ssoLogInStrategy.logIn(credentials);
expect(cryptoService.decryptUserSymKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
expect(cryptoService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
});
});
});

View File

@ -83,14 +83,14 @@ export class SsoLogInStrategy extends LogInStrategy {
const newSsoUser = tokenResponse.key == null;
if (!newSsoUser) {
await this.cryptoService.setUserSymKeyMasterKey(tokenResponse.key);
await this.cryptoService.setUserKeyMasterKey(tokenResponse.key);
if (tokenResponse.keyConnectorUrl != null) {
const masterKey = await this.cryptoService.getMasterKey();
if (!masterKey) {
throw new Error("Master key not found");
}
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setUserKey(userKey);
}
}

View File

@ -12,7 +12,7 @@ import { Utils } from "../../platform/misc/utils";
import {
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../../platform/models/domain/symmetric-crypto-key";
import { CsprngArray } from "../../types/csprng";
import { KeyConnectorService } from "../abstractions/key-connector.service";
@ -107,14 +107,14 @@ describe("UserApiLogInStrategy", () => {
expect(stateService.addAccount).toHaveBeenCalled();
});
it("sets the encrypted user symmetric key and private key from the identity token response", async () => {
it("sets the encrypted user key and private key from the identity token response", async () => {
const tokenResponse = identityTokenResponseFactory();
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
await apiLogInStrategy.logIn(credentials);
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
});
@ -130,10 +130,8 @@ describe("UserApiLogInStrategy", () => {
expect(keyConnectorService.getAndSetMasterKey).toHaveBeenCalledWith(keyConnectorUrl);
});
it("decrypts and sets the user symmetric key if Key Connector is enabled", async () => {
const userSymKey = new SymmetricCryptoKey(
new Uint8Array(64).buffer as CsprngArray
) as UserSymKey;
it("decrypts and sets the user key if Key Connector is enabled", async () => {
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
const tokenResponse = identityTokenResponseFactory();
@ -142,11 +140,11 @@ describe("UserApiLogInStrategy", () => {
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
environmentService.getKeyConnectorUrl.mockReturnValue(keyConnectorUrl);
cryptoService.getMasterKey.mockResolvedValue(masterKey);
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
await apiLogInStrategy.logIn(credentials);
expect(cryptoService.decryptUserSymKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
expect(cryptoService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
});
});

View File

@ -64,12 +64,12 @@ export class UserApiLogInStrategy extends LogInStrategy {
}
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
await this.cryptoService.setUserSymKeyMasterKey(response.key);
await this.cryptoService.setUserKeyMasterKey(response.key);
if (response.apiUseKeyConnector) {
const masterKey = await this.cryptoService.getMasterKey();
if (masterKey) {
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
await this.cryptoService.setUserKey(userKey);
}
}

View File

@ -297,7 +297,7 @@ export class AuthService implements AuthServiceAbstraction {
requestApproved: boolean
): Promise<AuthRequestResponse> {
// TODO: This currently depends on always having the Master Key and MP Hash
// We need to change this to using a different method (possibly server auth code + user sym key)
// We need to change this to using a different method (possibly server auth code + user key)
const pubKey = Utils.fromB64ToArray(key);
const masterKey = await this.cryptoService.getMasterKey();
if (!masterKey) {

View File

@ -97,9 +97,9 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
await this.cryptoService.setMasterKey(masterKey);
const userKey = await this.cryptoService.makeUserSymKey(masterKey);
const userKey = await this.cryptoService.makeUserKey(masterKey);
await this.cryptoService.setUserKey(userKey[0]);
await this.cryptoService.setUserSymKeyMasterKey(userKey[1].encryptedString);
await this.cryptoService.setUserKeyMasterKey(userKey[1].encryptedString);
const [pubKey, privKey] = await this.cryptoService.makeKeyPair();

View File

@ -10,90 +10,90 @@ import {
OrgKey,
PinKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../models/domain/symmetric-crypto-key";
export abstract class CryptoService {
/**
* Use for encryption/decryption of data in order to support legacy
* encryption models. It will return the user symmetric key if available,
* encryption models. It will return the user key if available,
* if not it will return the master key.
*/
getKeyForUserEncryption: (key?: SymmetricCryptoKey) => Promise<SymmetricCryptoKey>;
/**
* Sets the provided user symmetric key and stores
* Sets the provided user key and stores
* any other necessary versions, such as biometrics
* @param key The user symmetric key to set
* @param key The user key to set
* @param userId The desired user
*/
setUserKey: (key: UserSymKey) => Promise<void>;
setUserKey: (key: UserKey) => Promise<void>;
/**
* Gets the user key from memory and sets it again,
* kicking off a refresh of any additional keys that are needed.
*/
toggleKey: () => Promise<void>;
/**
* Retrieves the user's symmetric key
* Retrieves the user key
* @param keySuffix The desired version of the user's key to retrieve
* from storage if it is not available in memory
* @param userId The desired user
* @returns The user's symmetric key
* @returns The user key
*/
getUserKeyFromMemory: (userId?: string) => Promise<UserSymKey>;
getUserKeyFromMemory: (userId?: string) => Promise<UserKey>;
/**
* Retrieves the user's symmetric key from storage
* Retrieves the user key from storage
* @param keySuffix The desired version of the user's key to retrieve
* @param userId The desired user
* @returns The user's symmetric key
* @returns The user key
*/
getUserKeyFromStorage: (
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
userId?: string
) => Promise<UserSymKey>;
) => Promise<UserKey>;
/**
* @returns True if any version of the user symmetric key is available
* @returns True if any version of the user key is available
*/
hasUserKey: () => Promise<boolean>;
/**
* @param userId The desired user
* @returns True if the user symmetric key is set in memory
* @returns True if the user key is set in memory
*/
hasUserKeyInMemory: (userId?: string) => Promise<boolean>;
/**
* @param keySuffix The desired version of the user's key to check
* @param userId The desired user
* @returns True if the provided version of the user symmetric key is stored
* @returns True if the provided version of the user key is stored
*/
hasUserKeyStored: (
keySuffix?: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
userId?: string
) => Promise<boolean>;
/**
* Generates a new user symmetric key
* Generates a new user key
* @param masterKey The user's master key
* @returns A new user symmetric key and the master key protected version of it
* @returns A new user key and the master key protected version of it
*/
makeUserSymKey: (key: MasterKey) => Promise<[UserSymKey, EncString]>;
makeUserKey: (key: MasterKey) => Promise<[UserKey, EncString]>;
/**
* Clears the user's symmetric key
* Clears the user key
* @param clearStoredKeys Clears all stored versions of the user keys as well,
* such as the biometrics key
* @param userId The desired user
*/
clearUserKey: (clearSecretStorage?: boolean, userId?: string) => Promise<void>;
/**
* Clears the user's stored version of the user symmetric key
* Clears the user's stored version of the user key
* @param keySuffix The desired version of the key to clear
* @param userId The desired user
*/
clearStoredUserKey: (keySuffix: KeySuffixOptions, userId?: string) => Promise<void>;
/**
* Stores the master key encrypted user symmetric key
* @param userSymKeyMasterKey The master key encrypted user symmetric key to set
* Stores the master key encrypted user key
* @param userKeyMasterKey The master key encrypted user key to set
* @param userId The desired user
*/
setUserSymKeyMasterKey: (UserSymKeyMasterKey: string, userId?: string) => Promise<void>;
setUserKeyMasterKey: (UserKeyMasterKey: string, userId?: string) => Promise<void>;
/**
* Sets the user's master key
* @param key The user's master key to set
@ -125,28 +125,28 @@ export abstract class CryptoService {
*/
clearMasterKey: (userId?: string) => Promise<void>;
/**
* Encrypts the existing (or provided) user symmetric key with the
* Encrypts the existing (or provided) user key with the
* provided master key
* @param masterKey The user's master key
* @param userSymKey The user's symmetric key
* @returns The user's symmetric key and the master key protected version of it
* @param userKey The user key
* @returns The user key and the master key protected version of it
*/
encryptUserSymKeyWithMasterKey: (
encryptUserKeyWithMasterKey: (
masterKey: MasterKey,
userSymKey?: UserSymKey
) => Promise<[UserSymKey, EncString]>;
userKey?: UserKey
) => Promise<[UserKey, EncString]>;
/**
* Decrypts the user symmetric key with the provided master key
* Decrypts the user key with the provided master key
* @param masterKey The user's master key
* @param userSymKey The user's encrypted symmetric key
* @param userKey The user's encrypted symmetric key
* @param userId The desired user
* @returns The user's symmetric key
* @returns The user key
*/
decryptUserSymKeyWithMasterKey: (
decryptUserKeyWithMasterKey: (
masterKey: MasterKey,
userSymKey?: EncString,
userKey?: EncString,
userId?: string
) => Promise<UserSymKey>;
) => Promise<UserKey>;
/**
* Creates a master password hash from the user's master password. Can
* be used for local authentication or for server authentication depending
@ -265,7 +265,7 @@ export abstract class CryptoService {
/**
* Generates a new keypair
* @param key A key to encrypt the private key with. If not provided,
* defaults to the user's symmetric key
* defaults to the user key
* @returns A new keypair: [publicKey in Base64, encrypted privateKey]
*/
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
@ -284,7 +284,7 @@ export abstract class CryptoService {
*/
makePinKey: (pin: string, salt: string, kdf: KdfType, kdfConfig: KdfConfig) => Promise<PinKey>;
/**
* Clears the user's pin protected user symmetric key
* Clears the user's pin protected user key
* @param userId The desired user
*/
clearPinProtectedKey: (userId?: string) => Promise<void>;
@ -294,22 +294,22 @@ export abstract class CryptoService {
*/
clearOldPinKeys: (userId?: string) => Promise<void>;
/**
* Decrypts the user's symmetric key with their pin
* Decrypts the user key with their pin
* @param pin The user's PIN
* @param salt The user's salt
* @param kdf The user's KDF
* @param kdfConfig The user's KDF config
* @param pinProtectedUserSymKey The user's PIN protected symmetric key, if not provided
* @param pinProtectedUserKey The user's PIN protected symmetric key, if not provided
* it will be retrieved from storage
* @returns The decrypted user's symmetric key
* @returns The decrypted user key
*/
decryptUserSymKeyWithPin: (
decryptUserKeyWithPin: (
pin: string,
salt: string,
kdf: KdfType,
kdfConfig: KdfConfig,
protectedKeyCs?: EncString
) => Promise<UserSymKey>;
) => Promise<UserKey>;
/**
* @param keyMaterial The key material to derive the send key from
* @returns A new send key
@ -337,7 +337,7 @@ export abstract class CryptoService {
randomNumber: (min: number, max: number) => Promise<number>;
/**
* @deprecated Left for migration purposes. Use decryptUserSymKeyWithPin instead.
* @deprecated Left for migration purposes. Use decryptUserKeyWithPin instead.
*/
decryptMasterKeyWithPin: (
pin: string,

View File

@ -30,7 +30,7 @@ import {
DeviceKey,
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../models/domain/symmetric-crypto-key";
export abstract class StateService<T extends Account = Account> {
@ -78,13 +78,13 @@ export abstract class StateService<T extends Account = Account> {
getConvertAccountToKeyConnector: (options?: StorageOptions) => Promise<boolean>;
setConvertAccountToKeyConnector: (value: boolean, options?: StorageOptions) => Promise<void>;
/**
* gets the user's symmetric key
* gets the user key
*/
getUserSymKey: (options?: StorageOptions) => Promise<UserSymKey>;
getUserKey: (options?: StorageOptions) => Promise<UserKey>;
/**
* Sets the user's symmetric key
* Sets the user key
*/
setUserSymKey: (value: UserSymKey, options?: StorageOptions) => Promise<void>;
setUserKey: (value: UserKey, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's master key
*/
@ -94,59 +94,59 @@ export abstract class StateService<T extends Account = Account> {
*/
setMasterKey: (value: MasterKey, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's symmetric key encrypted by the master key
* Gets the user key encrypted by the master key
*/
getUserSymKeyMasterKey: (options?: StorageOptions) => Promise<string>;
getUserKeyMasterKey: (options?: StorageOptions) => Promise<string>;
/**
* Sets the user's symmetric key encrypted by the master key
* Sets the user key encrypted by the master key
*/
setUserSymKeyMasterKey: (value: string, options?: StorageOptions) => Promise<void>;
setUserKeyMasterKey: (value: string, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's auto key
*/
getUserSymKeyAuto: (options?: StorageOptions) => Promise<string>;
getUserKeyAuto: (options?: StorageOptions) => Promise<string>;
/**
* Sets the user's auto key
*/
setUserSymKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
setUserKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's biometric key
*/
getUserSymKeyBiometric: (options?: StorageOptions) => Promise<string>;
getUserKeyBiometric: (options?: StorageOptions) => Promise<string>;
/**
* Checks if the user has a biometric key available
*/
hasUserSymKeyBiometric: (options?: StorageOptions) => Promise<boolean>;
hasUserKeyBiometric: (options?: StorageOptions) => Promise<boolean>;
/**
* Sets the user's biometric key
*/
setUserSymKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
setUserKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's symmetric key encrypted by the Pin key.
* Gets the user key encrypted by the Pin key.
* Used when Master Password on Reset is disabled
*/
getUserSymKeyPin: (options?: StorageOptions) => Promise<EncString>;
getUserKeyPin: (options?: StorageOptions) => Promise<EncString>;
/**
* Sets the user's symmetric key encrypted by the Pin key.
* Sets the user key encrypted by the Pin key.
* Used when Master Password on Reset is disabled
*/
setUserSymKeyPin: (value: EncString, options?: StorageOptions) => Promise<void>;
setUserKeyPin: (value: EncString, options?: StorageOptions) => Promise<void>;
/**
* Gets the ephemeral version of the user's symmetric key encrypted by the Pin key.
* Gets the ephemeral version of the user key encrypted by the Pin key.
* Used when Master Password on Reset is enabled
*/
getUserSymKeyPinEphemeral: (options?: StorageOptions) => Promise<EncString>;
getUserKeyPinEphemeral: (options?: StorageOptions) => Promise<EncString>;
/**
* Sets the ephemeral version of the user's symmetric key encrypted by the Pin key.
* Sets the ephemeral version of the user key encrypted by the Pin key.
* Used when Master Password on Reset is enabled
*/
setUserSymKeyPinEphemeral: (value: EncString, options?: StorageOptions) => Promise<void>;
setUserKeyPinEphemeral: (value: EncString, options?: StorageOptions) => Promise<void>;
/**
* @deprecated For migration purposes only, use getUserSymKeyMasterKey instead
* @deprecated For migration purposes only, use getUserKeyMasterKey instead
*/
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
/**
* @deprecated For migration purposes only, use setUserSymKeyMasterKey instead
* @deprecated For migration purposes only, use setUserKeyMasterKey instead
*/
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
/**
@ -154,23 +154,23 @@ export abstract class StateService<T extends Account = Account> {
*/
getCryptoMasterKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
/**
* @deprecated For migration purposes only, use getUserSymKeyAuto instead
* @deprecated For migration purposes only, use getUserKeyAuto instead
*/
getCryptoMasterKeyAuto: (options?: StorageOptions) => Promise<string>;
/**
* @deprecated For migration purposes only, use setUserSymKeyAuto instead
* @deprecated For migration purposes only, use setUserKeyAuto instead
*/
setCryptoMasterKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
/**
* @deprecated For migration purposes only, use getUserSymKeyBiometric instead
* @deprecated For migration purposes only, use getUserKeyBiometric instead
*/
getCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<string>;
/**
* @deprecated For migration purposes only, use hasUserSymKeyBiometric instead
* @deprecated For migration purposes only, use hasUserKeyBiometric instead
*/
hasCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<boolean>;
/**
* @deprecated For migration purposes only, use setUserSymKeyBiometric instead
* @deprecated For migration purposes only, use setUserKeyBiometric instead
*/
setCryptoMasterKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
@ -192,11 +192,11 @@ export abstract class StateService<T extends Account = Account> {
options?: StorageOptions
) => Promise<void>;
/**
* @deprecated For migration purposes only, use getDecryptedUserSymKeyPin instead
* @deprecated For migration purposes only, use getDecryptedUserKeyPin instead
*/
getDecryptedPinProtected: (options?: StorageOptions) => Promise<EncString>;
/**
* @deprecated For migration purposes only, use setDecryptedUserSymKeyPin instead
* @deprecated For migration purposes only, use setDecryptedUserKeyPin instead
*/
setDecryptedPinProtected: (value: EncString, options?: StorageOptions) => Promise<void>;
/**
@ -325,11 +325,11 @@ export abstract class StateService<T extends Account = Account> {
options?: StorageOptions
) => Promise<void>;
/**
* @deprecated For migration purposes only, use getEncryptedUserSymKeyPin instead
* @deprecated For migration purposes only, use getEncryptedUserKeyPin instead
*/
getEncryptedPinProtected: (options?: StorageOptions) => Promise<string>;
/**
* @deprecated For migration purposes only, use setEncryptedUserSymKeyPin instead
* @deprecated For migration purposes only, use setEncryptedUserKeyPin instead
*/
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
/**
@ -426,11 +426,11 @@ export abstract class StateService<T extends Account = Account> {
getGeneratorOptions: (options?: StorageOptions) => Promise<any>;
setGeneratorOptions: (value: any, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's Pin, encrypted by the user symmetric key
* Gets the user's Pin, encrypted by the user key
*/
getProtectedPin: (options?: StorageOptions) => Promise<string>;
/**
* Sets the user's Pin, encrypted by the user symmetric key
* Sets the user's Pin, encrypted by the user key
*/
setProtectedPin: (value: string, options?: StorageOptions) => Promise<void>;
getProviders: (options?: StorageOptions) => Promise<{ [id: string]: ProviderData }>;

View File

@ -23,7 +23,7 @@ import { Utils } from "../../misc/utils";
import { ServerConfigData } from "../../models/data/server-config.data";
import { EncryptedString, EncString } from "./enc-string";
import { DeviceKey, MasterKey, SymmetricCryptoKey, UserSymKey } from "./symmetric-crypto-key";
import { DeviceKey, MasterKey, SymmetricCryptoKey, UserKey } from "./symmetric-crypto-key";
export class EncryptionPair<TEncrypted, TDecrypted> {
encrypted?: TEncrypted;
@ -99,11 +99,11 @@ export class AccountData {
}
export class AccountKeys {
userSymKey?: UserSymKey;
userKey?: UserKey;
masterKey?: MasterKey;
userSymKeyMasterKey?: string;
userSymKeyAuto?: string;
userSymKeyBiometric?: string;
userKeyMasterKey?: string;
userKeyAuto?: string;
userKeyBiometric?: string;
// deprecated keys
cryptoMasterKey?: SymmetricCryptoKey;
cryptoMasterKeyAuto?: string;
@ -141,7 +141,7 @@ export class AccountKeys {
}
return Object.assign(new AccountKeys(), {
userSymKey: SymmetricCryptoKey.fromJSON(obj?.userSymKey),
userKey: SymmetricCryptoKey.fromJSON(obj?.userKey),
masterKey: SymmetricCryptoKey.fromJSON(obj?.masterKey),
cryptoMasterKey: SymmetricCryptoKey.fromJSON(obj?.cryptoMasterKey),
cryptoSymmetricKey: EncryptionPair.fromJSON(
@ -232,8 +232,8 @@ export class AccountSettings {
passwordGenerationOptions?: any;
usernameGenerationOptions?: any;
generatorOptions?: any;
userSymKeyPin?: EncryptedString;
userSymKeyPinEphemeral?: EncryptedString;
userKeyPin?: EncryptedString;
userKeyPinEphemeral?: EncryptedString;
protectedPin?: string;
pinProtected?: EncryptionPair<string, EncString> = new EncryptionPair<string, EncString>(); // Deprecated
settings?: AccountSettingsSettings; // TODO: Merge whatever is going on here into the AccountSettings model properly

View File

@ -78,7 +78,7 @@ export class SymmetricCryptoKey {
// Setup all separate key types as opaque types
export type DeviceKey = Opaque<SymmetricCryptoKey, "DeviceKey">;
export type UserSymKey = Opaque<SymmetricCryptoKey, "UserSymKey">;
export type UserKey = Opaque<SymmetricCryptoKey, "UserKey">;
export type MasterKey = Opaque<SymmetricCryptoKey, "MasterKey">;
export type PinKey = Opaque<SymmetricCryptoKey, "PinKey">;
export type OrgKey = Opaque<SymmetricCryptoKey, "OrgKey">;

View File

@ -10,7 +10,7 @@ import {
MasterKey,
PinKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../models/domain/symmetric-crypto-key";
import { CryptoService } from "../services/crypto.service";
@ -44,33 +44,33 @@ describe("cryptoService", () => {
});
describe("getKeyForUserDecryption", () => {
let mockUserSymKey: UserSymKey;
let mockUserKey: UserKey;
let mockMasterKey: MasterKey;
let stateSvcGetUserSymKey: jest.SpyInstance;
let stateSvcGetUserKey: jest.SpyInstance;
let stateSvcGetMasterKey: jest.SpyInstance;
beforeEach(() => {
const mockRandomBytes = new Uint8Array(64).buffer as CsprngArray;
mockUserSymKey = new SymmetricCryptoKey(mockRandomBytes) as UserSymKey;
mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey;
mockMasterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
stateSvcGetUserSymKey = jest.spyOn(stateService, "getUserSymKey");
stateSvcGetUserKey = jest.spyOn(stateService, "getUserKey");
stateSvcGetMasterKey = jest.spyOn(stateService, "getMasterKey");
});
it("returns the user's symmetric key if available", async () => {
stateSvcGetUserSymKey.mockResolvedValue(mockUserSymKey);
it("returns the user key if available", async () => {
stateSvcGetUserKey.mockResolvedValue(mockUserKey);
const encryptionKey = await cryptoService.getKeyForUserEncryption();
expect(stateSvcGetUserSymKey).toHaveBeenCalled();
expect(stateSvcGetUserKey).toHaveBeenCalled();
expect(stateSvcGetMasterKey).not.toHaveBeenCalled();
expect(encryptionKey).toEqual(mockUserSymKey);
expect(encryptionKey).toEqual(mockUserKey);
});
it("returns the user's master key when symmetric key is not available", async () => {
stateSvcGetUserSymKey.mockResolvedValue(null);
stateSvcGetUserKey.mockResolvedValue(null);
stateSvcGetMasterKey.mockResolvedValue(mockMasterKey);
const encryptionKey = await cryptoService.getKeyForUserEncryption();
@ -82,32 +82,32 @@ describe("cryptoService", () => {
describe("setUserKey", () => {
const mockUserId = "example user id";
let mockUserSymKey: UserSymKey;
let mockUserKey: UserKey;
beforeEach(() => {
const mockRandomBytes = new Uint8Array(64).buffer as CsprngArray;
mockUserSymKey = new SymmetricCryptoKey(mockRandomBytes) as UserSymKey;
mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey;
});
it("saves an Auto key if needed", async () => {
stateService.getVaultTimeout.mockResolvedValue(null);
await cryptoService.setUserKey(mockUserSymKey, mockUserId);
await cryptoService.setUserKey(mockUserKey, mockUserId);
expect(stateService.setUserSymKeyAuto).toHaveBeenCalled();
expect(stateService.setUserSymKeyAuto).not.toHaveBeenCalledWith(null, { userId: mockUserId });
expect(stateService.setUserKeyAuto).toHaveBeenCalled();
expect(stateService.setUserKeyAuto).not.toHaveBeenCalledWith(null, { userId: mockUserId });
});
it("saves a Pin key if needed", async () => {
stateService.getUserSymKeyPinEphemeral.mockResolvedValue(null);
stateService.getUserKeyPinEphemeral.mockResolvedValue(null);
const cryptoSvcMakePinKey = jest.spyOn(cryptoService, "makePinKey");
cryptoSvcMakePinKey.mockResolvedValue(
new SymmetricCryptoKey(new Uint8Array(64).buffer) as PinKey
);
await cryptoService.setUserKey(mockUserSymKey, mockUserId);
await cryptoService.setUserKey(mockUserKey, mockUserId);
expect(stateService.setUserSymKeyPin).toHaveBeenCalled();
expect(stateService.setUserKeyPin).toHaveBeenCalled();
});
});
});

View File

@ -31,7 +31,7 @@ import {
OrgKey,
PinKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../models/domain/symmetric-crypto-key";
export class CryptoService implements CryptoServiceAbstraction {
@ -54,8 +54,8 @@ export class CryptoService implements CryptoServiceAbstraction {
return await this.getMasterKey();
}
async setUserKey(key: UserSymKey, userId?: string): Promise<void> {
await this.stateService.setUserSymKey(key, { userId: userId });
async setUserKey(key: UserKey, userId?: string): Promise<void> {
await this.stateService.setUserKey(key, { userId: userId });
await this.storeAdditionalKeys(key, userId);
}
@ -64,14 +64,14 @@ export class CryptoService implements CryptoServiceAbstraction {
await this.setUserKey(key);
}
async getUserKeyFromMemory(userId?: string): Promise<UserSymKey> {
return await this.stateService.getUserSymKey({ userId: userId });
async getUserKeyFromMemory(userId?: string): Promise<UserKey> {
return await this.stateService.getUserKey({ userId: userId });
}
async getUserKeyFromStorage(
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
userId?: string
): Promise<UserSymKey> {
): Promise<UserKey> {
const userKey = await this.retrieveUserKeyFromStorage(keySuffix, userId);
if (userKey != null) {
if (!(await this.validateUserKey(userKey))) {
@ -94,7 +94,7 @@ export class CryptoService implements CryptoServiceAbstraction {
}
async hasUserKeyInMemory(userId?: string): Promise<boolean> {
return (await this.stateService.getUserSymKey({ userId: userId })) != null;
return (await this.stateService.getUserKey({ userId: userId })) != null;
}
async hasUserKeyStored(
@ -103,23 +103,23 @@ export class CryptoService implements CryptoServiceAbstraction {
): Promise<boolean> {
if (keySuffix === KeySuffixOptions.Biometric) {
const oldKey = await this.stateService.hasCryptoMasterKeyBiometric({ userId: userId });
return oldKey || (await this.stateService.hasUserSymKeyBiometric({ userId: userId }));
return oldKey || (await this.stateService.hasUserKeyBiometric({ userId: userId }));
}
return (await this.retrieveUserKeyFromStorage(keySuffix, userId)) != null;
}
async makeUserSymKey(masterKey: MasterKey): Promise<[UserSymKey, EncString]> {
async makeUserKey(masterKey: MasterKey): Promise<[UserKey, EncString]> {
masterKey ||= await this.getMasterKey();
if (masterKey == null) {
throw new Error("No Master Key found.");
}
const newUserSymKey = await this.cryptoFunctionService.randomBytes(64);
return this.buildProtectedSymmetricKey(masterKey, newUserSymKey);
const newUserKey = await this.cryptoFunctionService.randomBytes(64);
return this.buildProtectedSymmetricKey(masterKey, newUserKey);
}
async clearUserKey(clearStoredKeys = true, userId?: string): Promise<void> {
await this.stateService.setUserSymKey(null, { userId: userId });
await this.stateService.setUserKey(null, { userId: userId });
if (clearStoredKeys) {
await this.clearAllStoredUserKeys(userId);
}
@ -128,19 +128,19 @@ export class CryptoService implements CryptoServiceAbstraction {
async clearStoredUserKey(keySuffix: KeySuffixOptions, userId?: string): Promise<void> {
switch (keySuffix) {
case KeySuffixOptions.Auto:
this.stateService.setUserSymKeyAuto(null, { userId: userId });
this.stateService.setUserKeyAuto(null, { userId: userId });
break;
case KeySuffixOptions.Biometric:
this.stateService.setUserSymKeyBiometric(null, { userId: userId });
this.stateService.setUserKeyBiometric(null, { userId: userId });
break;
case KeySuffixOptions.Pin:
this.stateService.setUserSymKeyPinEphemeral(null, { userId: userId });
this.stateService.setUserKeyPinEphemeral(null, { userId: userId });
break;
}
}
async setUserSymKeyMasterKey(userSymKeyMasterKey: string, userId?: string): Promise<void> {
await this.stateService.setUserSymKeyMasterKey(userSymKeyMasterKey, { userId: userId });
async setUserKeyMasterKey(userKeyMasterKey: string, userId?: string): Promise<void> {
await this.stateService.setUserKeyMasterKey(userKeyMasterKey, { userId: userId });
}
async setMasterKey(key: MasterKey, userId?: string): Promise<void> {
@ -166,40 +166,40 @@ export class CryptoService implements CryptoServiceAbstraction {
await this.stateService.setMasterKey(null, { userId: userId });
}
async encryptUserSymKeyWithMasterKey(
async encryptUserKeyWithMasterKey(
masterKey: MasterKey,
userSymKey?: UserSymKey
): Promise<[UserSymKey, EncString]> {
userSymKey ||= await this.getUserKeyFromMemory();
return this.buildProtectedSymmetricKey(masterKey, userSymKey.key);
userKey?: UserKey
): Promise<[UserKey, EncString]> {
userKey ||= await this.getUserKeyFromMemory();
return this.buildProtectedSymmetricKey(masterKey, userKey.key);
}
async decryptUserSymKeyWithMasterKey(
async decryptUserKeyWithMasterKey(
masterKey: MasterKey,
userSymKey?: EncString,
userKey?: EncString,
userId?: string
): Promise<UserSymKey> {
): Promise<UserKey> {
masterKey ||= await this.getMasterKey();
if (masterKey == null) {
throw new Error("No master key found.");
}
if (!userSymKey) {
const userSymKeyMasterKey = await this.stateService.getUserSymKeyMasterKey({
if (!userKey) {
const userKeyMasterKey = await this.stateService.getUserKeyMasterKey({
userId: userId,
});
if (userSymKeyMasterKey == null) {
if (userKeyMasterKey == null) {
throw new Error("No encrypted user key found.");
}
userSymKey = new EncString(userSymKeyMasterKey);
userKey = new EncString(userKeyMasterKey);
}
let decUserKey: ArrayBuffer;
if (userSymKey.encryptionType === EncryptionType.AesCbc256_B64) {
decUserKey = await this.decryptToBytes(userSymKey, masterKey);
} else if (userSymKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) {
if (userKey.encryptionType === EncryptionType.AesCbc256_B64) {
decUserKey = await this.decryptToBytes(userKey, masterKey);
} else if (userKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) {
const newKey = await this.stretchKey(masterKey);
decUserKey = await this.decryptToBytes(userSymKey, newKey);
decUserKey = await this.decryptToBytes(userKey, newKey);
} else {
throw new Error("Unsupported encryption type.");
}
@ -207,7 +207,7 @@ export class CryptoService implements CryptoServiceAbstraction {
return null;
}
return new SymmetricCryptoKey(decUserKey) as UserSymKey;
return new SymmetricCryptoKey(decUserKey) as UserKey;
}
async hashPassword(password: string, key: MasterKey, hashPurpose?: HashPurpose): Promise<string> {
@ -503,7 +503,7 @@ export class CryptoService implements CryptoServiceAbstraction {
}
async clearPinProtectedKey(userId?: string): Promise<void> {
await this.stateService.setUserSymKeyPin(null, { userId: userId });
await this.stateService.setUserKeyPin(null, { userId: userId });
await this.clearOldPinKeys(userId);
}
@ -512,20 +512,20 @@ export class CryptoService implements CryptoServiceAbstraction {
await this.stateService.setDecryptedPinProtected(null, { userId: userId });
}
async decryptUserSymKeyWithPin(
async decryptUserKeyWithPin(
pin: string,
salt: string,
kdf: KdfType,
kdfConfig: KdfConfig,
pinProtectedUserSymKey?: EncString
): Promise<UserSymKey> {
pinProtectedUserSymKey ||= await this.stateService.getUserSymKeyPin();
if (!pinProtectedUserSymKey) {
pinProtectedUserKey?: EncString
): Promise<UserKey> {
pinProtectedUserKey ||= await this.stateService.getUserKeyPin();
if (!pinProtectedUserKey) {
throw new Error("No PIN protected key found.");
}
const pinKey = await this.makePinKey(pin, salt, kdf, kdfConfig);
const userSymKey = await this.decryptToBytes(pinProtectedUserSymKey, pinKey);
return new SymmetricCryptoKey(userSymKey) as UserSymKey;
const userKey = await this.decryptToBytes(pinProtectedUserKey, pinKey);
return new SymmetricCryptoKey(userKey) as UserKey;
}
async decryptMasterKeyWithPin(
@ -669,7 +669,7 @@ export class CryptoService implements CryptoServiceAbstraction {
// ---HELPERS---
protected async validateUserKey(key?: UserSymKey): Promise<boolean> {
protected async validateUserKey(key?: UserKey): Promise<boolean> {
key ||= await this.getUserKeyFromMemory();
if (key == null) {
return false;
@ -692,27 +692,27 @@ export class CryptoService implements CryptoServiceAbstraction {
/**
* Regenerates any additional keys if needed. Useful to make sure
* other keys stay in sync when the user's symmetric key has been rotated.
* @param key The user's symmetric key
* other keys stay in sync when the user key has been rotated.
* @param key The user key
* @param userId The desired user
*/
protected async storeAdditionalKeys(key: UserSymKey, userId?: string) {
protected async storeAdditionalKeys(key: UserKey, userId?: string) {
const storeAuto = await this.shouldStoreKey(KeySuffixOptions.Auto, userId);
if (storeAuto) {
await this.stateService.setUserSymKeyAuto(key.keyB64, { userId: userId });
await this.stateService.setUserKeyAuto(key.keyB64, { userId: userId });
} else {
await this.stateService.setUserSymKeyAuto(null, { userId: userId });
await this.stateService.setUserKeyAuto(null, { userId: userId });
}
const storePin = await this.shouldStoreKey(KeySuffixOptions.Pin, userId);
if (storePin) {
await this.storePinKey(key);
} else {
await this.stateService.setUserSymKeyPin(null, { userId: userId });
await this.stateService.setUserKeyPin(null, { userId: userId });
}
}
protected async storePinKey(key: UserSymKey) {
protected async storePinKey(key: UserKey) {
const email = await this.stateService.getEmail();
const kdf = await this.stateService.getKdfType();
const kdfConfig = await this.stateService.getKdfConfig();
@ -721,7 +721,7 @@ export class CryptoService implements CryptoServiceAbstraction {
key
);
const pinKey = await this.makePinKey(pin, email, kdf, kdfConfig);
await this.stateService.setUserSymKeyPin(await this.encrypt(key.key, pinKey));
await this.stateService.setUserKeyPin(await this.encrypt(key.key, pinKey));
}
protected async shouldStoreKey(keySuffix: KeySuffixOptions, userId?: string) {
@ -741,10 +741,10 @@ export class CryptoService implements CryptoServiceAbstraction {
const protectedPin = await this.stateService.getProtectedPin({ userId: userId });
// This could cause a possible timing issue. Need to make sure the ephemeral key is set before
// we set our user key
const userSymKeyPinEphemeral = await this.stateService.getUserSymKeyPinEphemeral({
const userKeyPinEphemeral = await this.stateService.getUserKeyPinEphemeral({
userId: userId,
});
shouldStoreKey = !!protectedPin && !userSymKeyPinEphemeral;
shouldStoreKey = !!protectedPin && !userKeyPinEphemeral;
break;
}
}
@ -754,12 +754,12 @@ export class CryptoService implements CryptoServiceAbstraction {
protected async retrieveUserKeyFromStorage(
keySuffix: KeySuffixOptions,
userId?: string
): Promise<UserSymKey> {
): Promise<UserKey> {
if (keySuffix === KeySuffixOptions.Auto) {
await this.migrateAutoKeyIfNeeded(userId);
const userKey = await this.stateService.getUserSymKeyAuto({ userId: userId });
const userKey = await this.stateService.getUserKeyAuto({ userId: userId });
if (userKey) {
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserSymKey;
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserKey;
}
}
return null;
@ -772,12 +772,12 @@ export class CryptoService implements CryptoServiceAbstraction {
const masterKey = new SymmetricCryptoKey(
Utils.fromB64ToArray(oldAutoKey).buffer
) as MasterKey;
const userSymKey = await this.decryptUserSymKeyWithMasterKey(
const userKey = await this.decryptUserKeyWithMasterKey(
masterKey,
new EncString(await this.stateService.getEncryptedCryptoSymmetricKey())
);
// migrate
await this.stateService.setUserSymKeyAuto(userSymKey.keyB64, { userId: userId });
await this.stateService.setUserKeyAuto(userKey.keyB64, { userId: userId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
}
}
@ -828,9 +828,9 @@ export class CryptoService implements CryptoServiceAbstraction {
}
private async clearAllStoredUserKeys(userId?: string): Promise<void> {
await this.stateService.setUserSymKeyAuto(null, { userId: userId });
await this.stateService.setUserSymKeyBiometric(null, { userId: userId });
await this.stateService.setUserSymKeyPinEphemeral(null, { userId: userId });
await this.stateService.setUserKeyAuto(null, { userId: userId });
await this.stateService.setUserKeyBiometric(null, { userId: userId });
await this.stateService.setUserKeyPinEphemeral(null, { userId: userId });
}
async makeKey(

View File

@ -54,7 +54,7 @@ import {
DeviceKey,
MasterKey,
SymmetricCryptoKey,
UserSymKey,
UserKey,
} from "../models/domain/symmetric-crypto-key";
const keys = {
@ -69,7 +69,7 @@ const keys = {
const partialKeys = {
userAutoKey: "_user_auto",
userBiometricKey: "_user_biometric",
userSymKey: "_user_sym",
userKey: "_user_key",
autoKey: "_masterkey_auto",
biometricKey: "_masterkey_biometric",
@ -122,7 +122,7 @@ export class StateService<
// FIXME: This should be refactored into AuthService or a similar service,
// as checking for the existence of the crypto key is a low level
// implementation detail.
this.activeAccountUnlockedSubject.next((await this.getUserSymKey()) != null);
this.activeAccountUnlockedSubject.next((await this.getUserKey()) != null);
})
)
.subscribe();
@ -559,23 +559,23 @@ export class StateService<
}
/**
* User's symmetric key used to encrypt/decrypt data
* user key used to encrypt/decrypt data
*/
async getUserSymKey(options?: StorageOptions): Promise<UserSymKey> {
async getUserKey(options?: StorageOptions): Promise<UserKey> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultInMemoryOptions())
);
return account?.keys?.userSymKey as UserSymKey;
return account?.keys?.userKey as UserKey;
}
/**
* User's symmetric key used to encrypt/decrypt data
* user key used to encrypt/decrypt data
*/
async setUserSymKey(value: UserSymKey, options?: StorageOptions): Promise<void> {
async setUserKey(value: UserKey, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultInMemoryOptions())
);
account.keys.userSymKey = value;
account.keys.userKey = value;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultInMemoryOptions())
@ -619,21 +619,21 @@ export class StateService<
* The master key encrypted User symmetric key, saved on every auth
* so we can unlock with MP offline
*/
async getUserSymKeyMasterKey(options?: StorageOptions): Promise<string> {
async getUserKeyMasterKey(options?: StorageOptions): Promise<string> {
return (
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
)?.keys.userSymKeyMasterKey;
)?.keys.userKeyMasterKey;
}
/**
* The master key encrypted User symmetric key, saved on every auth
* so we can unlock with MP offline
*/
async setUserSymKeyMasterKey(value: string, options?: StorageOptions): Promise<void> {
async setUserKeyMasterKey(value: string, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
account.keys.userSymKeyMasterKey = value;
account.keys.userKeyMasterKey = value;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultOnDiskOptions())
@ -641,9 +641,9 @@ export class StateService<
}
/**
* User's symmetric key when using the "never" option of vault timeout
* user key when using the "never" option of vault timeout
*/
async getUserSymKeyAuto(options?: StorageOptions): Promise<string> {
async getUserKeyAuto(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "auto" }),
await this.defaultSecureStorageOptions()
@ -658,9 +658,9 @@ export class StateService<
}
/**
* User's symmetric key when using the "never" option of vault timeout
* user key when using the "never" option of vault timeout
*/
async setUserSymKeyAuto(value: string, options?: StorageOptions): Promise<void> {
async setUserKeyAuto(value: string, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "auto" }),
await this.defaultSecureStorageOptions()
@ -674,7 +674,7 @@ export class StateService<
/**
* User's encrypted symmetric key when using biometrics
*/
async getUserSymKeyBiometric(options?: StorageOptions): Promise<string> {
async getUserKeyBiometric(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "biometric" }),
await this.defaultSecureStorageOptions()
@ -688,7 +688,7 @@ export class StateService<
);
}
async hasUserSymKeyBiometric(options?: StorageOptions): Promise<boolean> {
async hasUserKeyBiometric(options?: StorageOptions): Promise<boolean> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "biometric" }),
await this.defaultSecureStorageOptions()
@ -702,7 +702,7 @@ export class StateService<
);
}
async setUserSymKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
async setUserKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "biometric" }),
await this.defaultSecureStorageOptions()
@ -713,36 +713,36 @@ export class StateService<
await this.saveSecureStorageKey(partialKeys.userBiometricKey, value, options);
}
async getUserSymKeyPin(options?: StorageOptions): Promise<EncString> {
async getUserKeyPin(options?: StorageOptions): Promise<EncString> {
return EncString.fromJSON(
(await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
?.settings?.userSymKeyPin
?.settings?.userKeyPin
);
}
async setUserSymKeyPin(value: EncString, options?: StorageOptions): Promise<void> {
async setUserKeyPin(value: EncString, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
account.settings.userSymKeyPin = value?.encryptedString;
account.settings.userKeyPin = value?.encryptedString;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
}
async getUserSymKeyPinEphemeral(options?: StorageOptions): Promise<EncString> {
async getUserKeyPinEphemeral(options?: StorageOptions): Promise<EncString> {
return EncString.fromJSON(
(await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions())))
?.settings?.userSymKeyPinEphemeral
?.settings?.userKeyPinEphemeral
);
}
async setUserSymKeyPinEphemeral(value: EncString, options?: StorageOptions): Promise<void> {
async setUserKeyPinEphemeral(value: EncString, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultInMemoryOptions())
);
account.settings.userSymKeyPinEphemeral = value?.encryptedString;
account.settings.userKeyPinEphemeral = value?.encryptedString;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultInMemoryOptions())
@ -750,7 +750,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKeyAuto instead
* @deprecated Use UserKeyAuto instead
*/
async getCryptoMasterKeyAuto(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(
@ -767,7 +767,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKeyAuto instead
* @deprecated Use UserKeyAuto instead
*/
async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
@ -806,7 +806,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKeyBiometric instead
* @deprecated Use UserKeyBiometric instead
*/
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(
@ -823,7 +823,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKeyBiometric instead
* @deprecated Use UserKeyBiometric instead
*/
async hasCryptoMasterKeyBiometric(options?: StorageOptions): Promise<boolean> {
options = this.reconcileOptions(
@ -840,7 +840,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKeyBiometric instead
* @deprecated Use UserKeyBiometric instead
*/
async setCryptoMasterKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
@ -890,7 +890,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKey instead
* @deprecated Use UserKey instead
*/
async getDecryptedCryptoSymmetricKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
const account = await this.getAccount(
@ -900,7 +900,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKey instead
* @deprecated Use UserKey instead
*/
async setDecryptedCryptoSymmetricKey(
value: SymmetricCryptoKey,
@ -1601,7 +1601,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKey instead
* @deprecated Use UserKey instead
*/
async getEncryptedCryptoSymmetricKey(options?: StorageOptions): Promise<string> {
return (
@ -1610,7 +1610,7 @@ export class StateService<
}
/**
* @deprecated Use UserSymKey instead
* @deprecated Use UserKey instead
*/
async setEncryptedCryptoSymmetricKey(value: string, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
@ -3018,8 +3018,8 @@ export class StateService<
protected async removeAccountFromSecureStorage(userId: string = null): Promise<void> {
userId = userId ?? (await this.state())?.activeUserId;
await this.setUserSymKeyAuto(null, { userId: userId });
await this.setUserSymKeyBiometric(null, { userId: userId });
await this.setUserKeyAuto(null, { userId: userId });
await this.setUserKeyBiometric(null, { userId: userId });
await this.setCryptoMasterKeyAuto(null, { userId: userId });
await this.setCryptoMasterKeyBiometric(null, { userId: userId });
await this.setCryptoMasterKeyB64(null, { userId: userId });

View File

@ -39,7 +39,7 @@ export class SystemService implements SystemServiceAbstraction {
}
// User has set a PIN, with ask for master password on restart, to protect their vault
const ephemeralPin = await this.stateService.getUserSymKeyPinEphemeral();
const ephemeralPin = await this.stateService.getUserKeyPinEphemeral();
if (ephemeralPin != null) {
return;
}

View File

@ -9,7 +9,7 @@ import { StateService } from "../platform/abstractions/state.service";
import {
SymmetricCryptoKey,
DeviceKey,
UserSymKey,
UserKey,
} from "../platform/models/domain/symmetric-crypto-key";
import { CsprngArray } from "../types/csprng";
@ -24,11 +24,11 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
) {}
async trustDevice(): Promise<DeviceResponse> {
// Attempt to get user symmetric key
const userSymKey: UserSymKey = await this.cryptoService.getUserKeyFromMemory();
// Attempt to get user key
const userKey: UserKey = await this.cryptoService.getUserKeyFromMemory();
// If user symmetric key is not found, throw error
if (!userSymKey) {
// If user key is not found, throw error
if (!userKey) {
throw new Error("User symmetric key not found");
}
@ -41,15 +41,15 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
);
const [
devicePublicKeyEncryptedUserSymKey,
userSymKeyEncryptedDevicePublicKey,
devicePublicKeyEncryptedUserKey,
userKeyEncryptedDevicePublicKey,
deviceKeyEncryptedDevicePrivateKey,
] = await Promise.all([
// Encrypt user symmetric key with the DevicePublicKey
this.cryptoService.rsaEncrypt(userSymKey.encKey, devicePublicKey),
// Encrypt user key with the DevicePublicKey
this.cryptoService.rsaEncrypt(userKey.encKey, devicePublicKey),
// Encrypt devicePublicKey with user symmetric key
this.encryptService.encrypt(devicePublicKey, userSymKey),
// Encrypt devicePublicKey with user key
this.encryptService.encrypt(devicePublicKey, userKey),
// Encrypt devicePrivateKey with deviceKey
this.encryptService.encrypt(devicePrivateKey, deviceKey),
@ -59,8 +59,8 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
const deviceIdentifier = await this.appIdService.getAppId();
return this.devicesApiService.updateTrustedDeviceKeys(
deviceIdentifier,
devicePublicKeyEncryptedUserSymKey.encryptedString,
userSymKeyEncryptedDevicePublicKey.encryptedString,
devicePublicKeyEncryptedUserKey.encryptedString,
userKeyEncryptedDevicePublicKey.encryptedString,
deviceKeyEncryptedDevicePrivateKey.encryptedString
);
}

View File

@ -11,7 +11,7 @@ import { EncString } from "../platform/models/domain/enc-string";
import {
SymmetricCryptoKey,
DeviceKey,
UserSymKey,
UserKey,
} from "../platform/models/domain/symmetric-crypto-key";
import { CryptoService } from "../platform/services/crypto.service";
import { CsprngArray } from "../types/csprng";
@ -51,7 +51,7 @@ describe("deviceCryptoService", () => {
describe("Trusted Device Encryption", () => {
const deviceKeyBytesLength = 64;
const userSymKeyBytesLength = 64;
const userKeyBytesLength = 64;
describe("getDeviceKey", () => {
let mockRandomBytes: CsprngArray;
@ -128,15 +128,15 @@ describe("deviceCryptoService", () => {
let mockDeviceKeyRandomBytes: CsprngArray;
let mockDeviceKey: DeviceKey;
let mockUserSymKeyRandomBytes: CsprngArray;
let mockUserSymKey: UserSymKey;
let mockUserKeyRandomBytes: CsprngArray;
let mockUserKey: UserKey;
const deviceRsaKeyLength = 2048;
let mockDeviceRsaKeyPair: [ArrayBuffer, ArrayBuffer];
let mockDevicePrivateKey: ArrayBuffer;
let mockDevicePublicKey: ArrayBuffer;
let mockDevicePublicKeyEncryptedUserSymKey: EncString;
let mockUserSymKeyEncryptedDevicePublicKey: EncString;
let mockDevicePublicKeyEncryptedUserKey: EncString;
let mockUserKeyEncryptedDevicePublicKey: EncString;
let mockDeviceKeyEncryptedDevicePrivateKey: EncString;
const mockDeviceResponse: DeviceResponse = new DeviceResponse({
@ -163,8 +163,8 @@ describe("deviceCryptoService", () => {
mockDeviceKeyRandomBytes = new Uint8Array(deviceKeyBytesLength).buffer as CsprngArray;
mockDeviceKey = new SymmetricCryptoKey(mockDeviceKeyRandomBytes) as DeviceKey;
mockUserSymKeyRandomBytes = new Uint8Array(userSymKeyBytesLength).buffer as CsprngArray;
mockUserSymKey = new SymmetricCryptoKey(mockUserSymKeyRandomBytes) as UserSymKey;
mockUserKeyRandomBytes = new Uint8Array(userKeyBytesLength).buffer as CsprngArray;
mockUserKey = new SymmetricCryptoKey(mockUserKeyRandomBytes) as UserKey;
mockDeviceRsaKeyPair = [
new ArrayBuffer(deviceRsaKeyLength),
@ -174,14 +174,14 @@ describe("deviceCryptoService", () => {
mockDevicePublicKey = mockDeviceRsaKeyPair[0];
mockDevicePrivateKey = mockDeviceRsaKeyPair[1];
mockDevicePublicKeyEncryptedUserSymKey = new EncString(
mockDevicePublicKeyEncryptedUserKey = new EncString(
EncryptionType.Rsa2048_OaepSha1_B64,
"mockDevicePublicKeyEncryptedUserSymKey"
"mockDevicePublicKeyEncryptedUserKey"
);
mockUserSymKeyEncryptedDevicePublicKey = new EncString(
mockUserKeyEncryptedDevicePublicKey = new EncString(
EncryptionType.AesCbc256_HmacSha256_B64,
"mockUserSymKeyEncryptedDevicePublicKey"
"mockUserKeyEncryptedDevicePublicKey"
);
mockDeviceKeyEncryptedDevicePrivateKey = new EncString(
@ -200,17 +200,17 @@ describe("deviceCryptoService", () => {
cryptoSvcGetUserKeyFromMemorySpy = jest
.spyOn(cryptoService, "getUserKeyFromMemory")
.mockResolvedValue(mockUserSymKey);
.mockResolvedValue(mockUserKey);
cryptoSvcRsaEncryptSpy = jest
.spyOn(cryptoService, "rsaEncrypt")
.mockResolvedValue(mockDevicePublicKeyEncryptedUserSymKey);
.mockResolvedValue(mockDevicePublicKeyEncryptedUserKey);
encryptServiceEncryptSpy = jest
.spyOn(encryptService, "encrypt")
.mockImplementation((plainValue, key) => {
if (plainValue === mockDevicePublicKey && key === mockUserSymKey) {
return Promise.resolve(mockUserSymKeyEncryptedDevicePublicKey);
if (plainValue === mockDevicePublicKey && key === mockUserKey) {
return Promise.resolve(mockUserKeyEncryptedDevicePublicKey);
}
if (plainValue === mockDevicePrivateKey && key === mockDeviceKey) {
return Promise.resolve(mockDeviceKeyEncryptedDevicePrivateKey);
@ -240,8 +240,8 @@ describe("deviceCryptoService", () => {
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledTimes(1);
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledWith(
mockDeviceId,
mockDevicePublicKeyEncryptedUserSymKey.encryptedString,
mockUserSymKeyEncryptedDevicePublicKey.encryptedString,
mockDevicePublicKeyEncryptedUserKey.encryptedString,
mockUserKeyEncryptedDevicePublicKey.encryptedString,
mockDeviceKeyEncryptedDevicePrivateKey.encryptedString
);
@ -249,7 +249,7 @@ describe("deviceCryptoService", () => {
expect(response).toEqual(mockDeviceResponse);
});
it("throws specific error if user symmetric key is not found", async () => {
it("throws specific error if user key is not found", async () => {
// setup the spy to return null
cryptoSvcGetUserKeyFromMemorySpy.mockResolvedValue(null);
// check if the expected error is thrown

View File

@ -41,13 +41,13 @@ export class DevicesApiServiceImplementation implements DevicesApiServiceAbstrac
async updateTrustedDeviceKeys(
deviceIdentifier: string,
devicePublicKeyEncryptedUserSymKey: string,
userSymKeyEncryptedDevicePublicKey: string,
devicePublicKeyEncryptedUserKey: string,
userKeyEncryptedDevicePublicKey: string,
deviceKeyEncryptedDevicePrivateKey: string
): Promise<DeviceResponse> {
const request = new TrustedDeviceKeysRequest(
devicePublicKeyEncryptedUserSymKey,
userSymKeyEncryptedDevicePublicKey,
devicePublicKeyEncryptedUserKey,
userKeyEncryptedDevicePublicKey,
deviceKeyEncryptedDevicePrivateKey
);

View File

@ -72,7 +72,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
if (await this.keyConnectorService.getUsesKeyConnector()) {
const pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
let ephemeralPinSet = await this.stateService.getUserSymKeyPinEphemeral();
let ephemeralPinSet = await this.stateService.getUserKeyPinEphemeral();
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
const pinLock = (pinSet[0] && ephemeralPinSet != null) || pinSet[1];
@ -87,7 +87,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}
await this.stateService.setEverBeenUnlocked(true, { userId: userId });
await this.stateService.setUserSymKeyAuto(null, { userId: userId });
await this.stateService.setUserKeyAuto(null, { userId: userId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
await this.cryptoService.clearUserKey(false, userId);

View File

@ -48,12 +48,12 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
// we can't check the protected pin for both because old accounts only
// used it for MP on Restart
const pinIsEnabled = !!(await this.stateService.getProtectedPin());
const aUserSymKeyPinIsSet = !!(await this.stateService.getUserSymKeyPin());
const anOldUserSymKeyPinIsSet = !!(await this.stateService.getEncryptedPinProtected());
const aUserKeyPinIsSet = !!(await this.stateService.getUserKeyPin());
const anOldUserKeyPinIsSet = !!(await this.stateService.getEncryptedPinProtected());
return [
pinIsEnabled && !aUserSymKeyPinIsSet && !anOldUserSymKeyPinIsSet,
aUserSymKeyPinIsSet || anOldUserSymKeyPinIsSet,
pinIsEnabled && !aUserKeyPinIsSet && !anOldUserKeyPinIsSet,
aUserKeyPinIsSet || anOldUserKeyPinIsSet,
];
}
@ -111,7 +111,7 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
async clear(userId?: string): Promise<void> {
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
await this.stateService.setUserSymKeyPinEphemeral(null, { userId: userId });
await this.stateService.setUserKeyPinEphemeral(null, { userId: userId });
await this.stateService.setProtectedPin(null, { userId: userId });
await this.cryptoService.clearOldPinKeys(userId);
}

View File

@ -303,7 +303,7 @@ export class SyncService implements SyncServiceAbstraction {
throw new Error("Stamp has changed");
}
await this.cryptoService.setUserSymKeyMasterKey(response.key);
await this.cryptoService.setUserKeyMasterKey(response.key);
await this.cryptoService.setPrivateKey(response.privateKey);
await this.cryptoService.setProviderKeys(response.providers);
await this.cryptoService.setOrgKeys(response.organizations, response.providerOrganizations);