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:
parent
e4bfa62e70
commit
6349410ec2
@ -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)
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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()) {
|
||||
|
@ -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/"
|
||||
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -7,8 +7,8 @@ export abstract class DevicesApiServiceAbstraction {
|
||||
|
||||
updateTrustedDeviceKeys: (
|
||||
deviceIdentifier: string,
|
||||
devicePublicKeyEncryptedUserSymKey: string,
|
||||
userSymKeyEncryptedDevicePublicKey: string,
|
||||
devicePublicKeyEncryptedUserKey: string,
|
||||
userKeyEncryptedDevicePublicKey: string,
|
||||
deviceKeyEncryptedDevicePrivateKey: string
|
||||
) => Promise<DeviceResponse>;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 }>;
|
||||
|
@ -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
|
||||
|
@ -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">;
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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 });
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user