mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-02 13:23:29 +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 {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import { BrowserApi } from "../platform/browser/browser-api";
|
import { BrowserApi } from "../platform/browser/browser-api";
|
||||||
@ -329,19 +329,19 @@ export class NativeMessagingBackground {
|
|||||||
if (message.userKeyB64) {
|
if (message.userKeyB64) {
|
||||||
const userKey = new SymmetricCryptoKey(
|
const userKey = new SymmetricCryptoKey(
|
||||||
Utils.fromB64ToArray(message.userKeyB64).buffer
|
Utils.fromB64ToArray(message.userKeyB64).buffer
|
||||||
) as UserSymKey;
|
) as UserKey;
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
} else if (message.keyB64) {
|
} else if (message.keyB64) {
|
||||||
// backwards compatibility
|
// backwards compatibility
|
||||||
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||||
encUserKey ||= await this.stateService.getUserSymKeyMasterKey();
|
encUserKey ||= await this.stateService.getUserKeyMasterKey();
|
||||||
if (!encUserKey) {
|
if (!encUserKey) {
|
||||||
throw new Error("No encrypted user key found");
|
throw new Error("No encrypted user key found");
|
||||||
}
|
}
|
||||||
const masterKey = new SymmetricCryptoKey(
|
const masterKey = new SymmetricCryptoKey(
|
||||||
Utils.fromB64ToArray(message.keyB64).buffer
|
Utils.fromB64ToArray(message.keyB64).buffer
|
||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
|
||||||
masterKey,
|
masterKey,
|
||||||
new EncString(encUserKey)
|
new EncString(encUserKey)
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@ import { KeySuffixOptions } from "@bitwarden/common/enums";
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import {
|
import {
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||||
|
|
||||||
@ -10,12 +10,12 @@ export class BrowserCryptoService extends CryptoService {
|
|||||||
protected override async retrieveUserKeyFromStorage(
|
protected override async retrieveUserKeyFromStorage(
|
||||||
keySuffix: KeySuffixOptions,
|
keySuffix: KeySuffixOptions,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||||
await this.platformUtilService.authenticateBiometric();
|
await this.platformUtilService.authenticateBiometric();
|
||||||
const userKey = await this.getUserKeyFromMemory();
|
const userKey = await this.getUserKeyFromMemory();
|
||||||
if (userKey) {
|
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 {
|
try {
|
||||||
const {
|
const {
|
||||||
newPasswordHash,
|
newPasswordHash,
|
||||||
newUserSymKey: newEncKey,
|
newUserKey: newEncKey,
|
||||||
hint,
|
hint,
|
||||||
} = await this.collectNewMasterPasswordDetails(
|
} = 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."
|
"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 {
|
try {
|
||||||
const {
|
const {
|
||||||
newPasswordHash,
|
newPasswordHash,
|
||||||
newUserSymKey: newEncKey,
|
newUserKey: newEncKey,
|
||||||
hint,
|
hint,
|
||||||
} = await this.collectNewMasterPasswordDetails(
|
} = await this.collectNewMasterPasswordDetails(
|
||||||
"An organization administrator recently changed your master password. In order to access the vault, you must update your master password now."
|
"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
|
* Collect new master password and hint from the CLI. The collected password
|
||||||
* is validated against any applicable master password policies, a new master
|
* 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 prompt - Message that is displayed during the initial prompt
|
||||||
* @param error
|
* @param error
|
||||||
*/
|
*/
|
||||||
@ -485,7 +485,7 @@ export class LoginCommand {
|
|||||||
error?: string
|
error?: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
newPasswordHash: string;
|
newPasswordHash: string;
|
||||||
newUserSymKey: [SymmetricCryptoKey, EncString];
|
newUserKey: [SymmetricCryptoKey, EncString];
|
||||||
hint?: string;
|
hint?: string;
|
||||||
}> {
|
}> {
|
||||||
if (this.email == null || this.email === "undefined") {
|
if (this.email == null || this.email === "undefined") {
|
||||||
@ -575,19 +575,16 @@ export class LoginCommand {
|
|||||||
);
|
);
|
||||||
const newPasswordHash = await this.cryptoService.hashPassword(masterPassword, newMasterKey);
|
const newPasswordHash = await this.cryptoService.hashPassword(masterPassword, newMasterKey);
|
||||||
|
|
||||||
// Grab user's symmetric key
|
// Grab user key
|
||||||
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
|
const userKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
if (!userSymKey) {
|
if (!userKey) {
|
||||||
throw new Error("User key not found.");
|
throw new Error("User key not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-encrypt user's symmetric key with new master key
|
// Re-encrypt user key with new master key
|
||||||
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
|
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey, userKey);
|
||||||
newMasterKey,
|
|
||||||
userSymKey
|
|
||||||
);
|
|
||||||
|
|
||||||
return { newPasswordHash, newUserSymKey, hint: masterPasswordHint };
|
return { newPasswordHash, newUserKey: newUserKey, hint: masterPasswordHint };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleCaptchaRequired(
|
private async handleCaptchaRequired(
|
||||||
|
@ -76,7 +76,7 @@ export class UnlockCommand {
|
|||||||
|
|
||||||
if (passwordValid) {
|
if (passwordValid) {
|
||||||
await this.cryptoService.setMasterKey(masterKey);
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
|
|
||||||
if (await this.keyConnectorService.getConvertAccountRequired()) {
|
if (await this.keyConnectorService.getConvertAccountRequired()) {
|
||||||
|
@ -126,8 +126,8 @@ export class CreateCommand {
|
|||||||
return Response.error("Premium status is required to use this feature.");
|
return Response.error("Premium status is required to use this feature.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
|
const userKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
if (userSymKey == null) {
|
if (userKey == null) {
|
||||||
return Response.error(
|
return Response.error(
|
||||||
"You must update your encryption key before you can use this feature. " +
|
"You must update your encryption key before you can use this feature. " +
|
||||||
"See https://help.bitwarden.com/article/update-encryption-key/"
|
"See https://help.bitwarden.com/article/update-encryption-key/"
|
||||||
|
@ -8,7 +8,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||||
import { CsprngString } from "@bitwarden/common/types/csprng";
|
import { CsprngString } from "@bitwarden/common/types/csprng";
|
||||||
@ -26,7 +26,7 @@ export class ElectronCryptoService extends CryptoService {
|
|||||||
super(cryptoFunctionService, encryptService, platformUtilsService, logService, stateService);
|
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);
|
await super.storeAdditionalKeys(key, userId);
|
||||||
|
|
||||||
const storeBiometricKey = await this.shouldStoreKey(KeySuffixOptions.Biometric, userId);
|
const storeBiometricKey = await this.shouldStoreKey(KeySuffixOptions.Biometric, userId);
|
||||||
@ -34,28 +34,28 @@ export class ElectronCryptoService extends CryptoService {
|
|||||||
if (storeBiometricKey) {
|
if (storeBiometricKey) {
|
||||||
await this.storeBiometricKey(key, userId);
|
await this.storeBiometricKey(key, userId);
|
||||||
} else {
|
} else {
|
||||||
await this.stateService.setUserSymKeyBiometric(null, { userId: userId });
|
await this.stateService.setUserKeyBiometric(null, { userId: userId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async retrieveUserKeyFromStorage(
|
protected override async retrieveUserKeyFromStorage(
|
||||||
keySuffix: KeySuffixOptions,
|
keySuffix: KeySuffixOptions,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||||
await this.migrateBiometricKeyIfNeeded(userId);
|
await this.migrateBiometricKeyIfNeeded(userId);
|
||||||
const userKey = await this.stateService.getUserSymKeyBiometric({ userId: userId });
|
const userKey = await this.stateService.getUserKeyBiometric({ userId: userId });
|
||||||
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserSymKey;
|
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserKey;
|
||||||
}
|
}
|
||||||
return await super.retrieveUserKeyFromStorage(keySuffix, userId);
|
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;
|
let clientEncKeyHalf: CsprngString = null;
|
||||||
if (await this.stateService.getBiometricRequirePasswordOnStart({ userId })) {
|
if (await this.stateService.getBiometricRequirePasswordOnStart({ userId })) {
|
||||||
clientEncKeyHalf = await this.getBiometricEncryptionClientKeyHalf(userId);
|
clientEncKeyHalf = await this.getBiometricEncryptionClientKeyHalf(userId);
|
||||||
}
|
}
|
||||||
await this.stateService.setUserSymKeyBiometric(
|
await this.stateService.setUserKeyBiometric(
|
||||||
{ key: key.keyB64, clientEncKeyHalf },
|
{ key: key.keyB64, clientEncKeyHalf },
|
||||||
{ userId: userId }
|
{ userId: userId }
|
||||||
);
|
);
|
||||||
@ -87,16 +87,13 @@ export class ElectronCryptoService extends CryptoService {
|
|||||||
// decrypt
|
// decrypt
|
||||||
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
|
||||||
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||||
encUserKey = encUserKey ?? (await this.stateService.getUserSymKeyMasterKey());
|
encUserKey = encUserKey ?? (await this.stateService.getUserKeyMasterKey());
|
||||||
if (!encUserKey) {
|
if (!encUserKey) {
|
||||||
throw new Error("No user key found during biometric migration");
|
throw new Error("No user key found during biometric migration");
|
||||||
}
|
}
|
||||||
const userSymKey = await this.decryptUserSymKeyWithMasterKey(
|
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, new EncString(encUserKey));
|
||||||
masterKey,
|
|
||||||
new EncString(encUserKey)
|
|
||||||
);
|
|
||||||
// migrate
|
// migrate
|
||||||
await this.storeBiometricKey(userSymKey, userId);
|
await this.storeBiometricKey(userKey, userId);
|
||||||
await this.stateService.setCryptoMasterKeyBiometric(null, { 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import {
|
import {
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
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
|
// Decrypt User's Reset Password Key to get EncKey
|
||||||
const decValue = await this.cryptoService.rsaDecrypt(resetPasswordKey, decPrivateKey);
|
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
|
// Create new master key and hash new password
|
||||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||||
@ -190,15 +190,15 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
|
|||||||
newMasterKey
|
newMasterKey
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create new encrypted user symmetric key for the User
|
// Create new encrypted user key for the User
|
||||||
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
|
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(
|
||||||
newMasterKey,
|
newMasterKey,
|
||||||
existingUserSymKey
|
existingUserKey
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
const request = new OrganizationUserResetPasswordRequest();
|
const request = new OrganizationUserResetPasswordRequest();
|
||||||
request.key = newUserSymKey[1].encryptedString;
|
request.key = newUserKey[1].encryptedString;
|
||||||
request.newMasterPasswordHash = newPasswordHash;
|
request.newMasterPasswordHash = newPasswordHash;
|
||||||
|
|
||||||
// Change user's password
|
// 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 { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import {
|
import {
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
|
||||||
@ -94,9 +94,9 @@ export class EmergencyAccessTakeoverComponent
|
|||||||
);
|
);
|
||||||
|
|
||||||
const oldKeyBuffer = await this.cryptoService.rsaDecrypt(takeoverResponse.keyEncrypted);
|
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(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
this.i18nService.t("errorOccurred"),
|
this.i18nService.t("errorOccurred"),
|
||||||
@ -120,10 +120,7 @@ export class EmergencyAccessTakeoverComponent
|
|||||||
masterKey
|
masterKey
|
||||||
);
|
);
|
||||||
|
|
||||||
const encKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
|
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, oldUserKey);
|
||||||
masterKey,
|
|
||||||
oldUserSymKey
|
|
||||||
);
|
|
||||||
|
|
||||||
const request = new EmergencyAccessPasswordRequest();
|
const request = new EmergencyAccessPasswordRequest();
|
||||||
request.newMasterPasswordHash = masterPasswordHash;
|
request.newMasterPasswordHash = masterPasswordHash;
|
||||||
|
@ -77,8 +77,8 @@ export class ChangeEmailComponent implements OnInit {
|
|||||||
this.masterPassword,
|
this.masterPassword,
|
||||||
newMasterKey
|
newMasterKey
|
||||||
);
|
);
|
||||||
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(newMasterKey);
|
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
|
||||||
request.key = newUserSymKey[1].encryptedString;
|
request.key = newUserKey[1].encryptedString;
|
||||||
try {
|
try {
|
||||||
this.formPromise = this.apiService.postEmail(request);
|
this.formPromise = this.apiService.postEmail(request);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
|
@ -87,8 +87,8 @@ export class ChangeKdfConfirmationComponent {
|
|||||||
masterPassword,
|
masterPassword,
|
||||||
newMasterKey
|
newMasterKey
|
||||||
);
|
);
|
||||||
const newUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(newMasterKey);
|
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
|
||||||
request.key = newUserSymKey[1].encryptedString;
|
request.key = newUserKey[1].encryptedString;
|
||||||
|
|
||||||
await this.apiService.postAccountKdf(request);
|
await this.apiService.postAccountKdf(request);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { SendWithIdRequest } from "@bitwarden/common/tools/send/models/request/send-with-id.request";
|
import { SendWithIdRequest } from "@bitwarden/common/tools/send/models/request/send-with-id.request";
|
||||||
@ -184,7 +184,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
async performSubmitActions(
|
async performSubmitActions(
|
||||||
newMasterPasswordHash: string,
|
newMasterPasswordHash: string,
|
||||||
newMasterKey: MasterKey,
|
newMasterKey: MasterKey,
|
||||||
newUserKey: [UserSymKey, EncString]
|
newUserKey: [UserKey, EncString]
|
||||||
) {
|
) {
|
||||||
const request = new PasswordRequest();
|
const request = new PasswordRequest();
|
||||||
request.masterPasswordHash = await this.cryptoService.hashPassword(
|
request.masterPasswordHash = await this.cryptoService.hashPassword(
|
||||||
@ -218,15 +218,15 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async updateKey(masterKey: MasterKey, masterPasswordHash: string) {
|
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();
|
const privateKey = await this.cryptoService.getPrivateKey();
|
||||||
let encPrivateKey: EncString = null;
|
let encPrivateKey: EncString = null;
|
||||||
if (privateKey != null) {
|
if (privateKey != null) {
|
||||||
encPrivateKey = await this.cryptoService.encrypt(privateKey, userSymKey[0]);
|
encPrivateKey = await this.cryptoService.encrypt(privateKey, userKey[0]);
|
||||||
}
|
}
|
||||||
const request = new UpdateKeyRequest();
|
const request = new UpdateKeyRequest();
|
||||||
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
|
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
|
||||||
request.key = userSymKey[1].encryptedString;
|
request.key = userKey[1].encryptedString;
|
||||||
request.masterPasswordHash = masterPasswordHash;
|
request.masterPasswordHash = masterPasswordHash;
|
||||||
|
|
||||||
const folders = await firstValueFrom(this.folderService.folderViews$);
|
const folders = await firstValueFrom(this.folderService.folderViews$);
|
||||||
@ -234,7 +234,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
if (folders[i].id == null) {
|
if (folders[i].id == null) {
|
||||||
continue;
|
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));
|
request.folders.push(new FolderWithIdRequest(folder));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
continue;
|
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));
|
request.ciphers.push(new CipherWithIdRequest(cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,16 +252,16 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
sends.map(async (send) => {
|
sends.map(async (send) => {
|
||||||
const sendKey = await this.cryptoService.decryptToBytes(send.key, null);
|
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));
|
request.sends.push(new SendWithIdRequest(send));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.apiService.postAccountKey(request);
|
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) {
|
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();
|
const orgs = await this.organizationService.getAll();
|
||||||
|
|
||||||
for (const org of orgs) {
|
for (const org of orgs) {
|
||||||
@ -303,7 +303,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
const publicKey = Utils.fromB64ToArray(response?.publicKey);
|
const publicKey = Utils.fromB64ToArray(response?.publicKey);
|
||||||
|
|
||||||
// Re-enroll - encrypt user's encKey.key with organization public key
|
// 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
|
// Create/Execute request
|
||||||
const request = new OrganizationUserResetPasswordEnrollmentRequest();
|
const request = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||||
|
@ -69,7 +69,7 @@ export class UpdateKeyComponent {
|
|||||||
|
|
||||||
private async makeRequest(): Promise<UpdateKeyRequest> {
|
private async makeRequest(): Promise<UpdateKeyRequest> {
|
||||||
const masterKey = await this.cryptoService.getMasterKey();
|
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();
|
const privateKey = await this.cryptoService.getPrivateKey();
|
||||||
let encPrivateKey: EncString = null;
|
let encPrivateKey: EncString = null;
|
||||||
if (privateKey != 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 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) {}
|
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 devicePublicKey
|
||||||
* @param resetPasswordDetails
|
* @param resetPasswordDetails
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private async getEncryptedUserSymKey(
|
private async getEncryptedUserKey(
|
||||||
devicePublicKey: string,
|
devicePublicKey: string,
|
||||||
resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse
|
resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse
|
||||||
): Promise<EncString> {
|
): Promise<EncString> {
|
||||||
const encryptedUserSymKey = resetPasswordDetails.resetPasswordKey;
|
const encryptedUserKey = resetPasswordDetails.resetPasswordKey;
|
||||||
const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey;
|
const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey;
|
||||||
const devicePubKey = Utils.fromB64ToArray(devicePublicKey);
|
const devicePubKey = Utils.fromB64ToArray(devicePublicKey);
|
||||||
|
|
||||||
@ -85,12 +85,12 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
|
|||||||
orgSymKey
|
orgSymKey
|
||||||
);
|
);
|
||||||
|
|
||||||
// Decrypt User's symmetric key with decrypted org private key
|
// Decrypt user key with decrypted org private key
|
||||||
const decValue = await this.cryptoService.rsaDecrypt(encryptedUserSymKey, decOrgPrivateKey);
|
const decValue = await this.cryptoService.rsaDecrypt(encryptedUserKey, decOrgPrivateKey);
|
||||||
const userSymKey = new SymmetricCryptoKey(decValue);
|
const userKey = new SymmetricCryptoKey(decValue);
|
||||||
|
|
||||||
// Re-encrypt User's Symmetric Key with the Device Public Key
|
// Re-encrypt user Key with the Device Public Key
|
||||||
return await this.cryptoService.rsaEncrypt(userSymKey.key, devicePubKey.buffer);
|
return await this.cryptoService.rsaEncrypt(userKey.key, devicePubKey.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async approveRequest(authRequest: PendingAuthRequestView) {
|
async approveRequest(authRequest: PendingAuthRequestView) {
|
||||||
@ -110,7 +110,7 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedKey = await this.getEncryptedUserSymKey(authRequest.publicKey, details);
|
const encryptedKey = await this.getEncryptedUserKey(authRequest.publicKey, details);
|
||||||
|
|
||||||
await this.organizationAuthRequestService.approvePendingRequest(
|
await this.organizationAuthRequestService.approvePendingRequest(
|
||||||
this.organizationId,
|
this.organizationId,
|
||||||
|
@ -12,10 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import {
|
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
MasterKey,
|
|
||||||
UserSymKey,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
|
||||||
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
|
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
|
||||||
@ -95,17 +92,15 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
|
|||||||
newMasterKey
|
newMasterKey
|
||||||
);
|
);
|
||||||
|
|
||||||
let newProtectedUserSymKey: [UserSymKey, EncString] = null;
|
let newProtectedUserKey: [UserKey, EncString] = null;
|
||||||
const userSymKey = await this.cryptoService.getUserKeyFromMemory();
|
const userKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
if (userSymKey == null) {
|
if (userKey == null) {
|
||||||
newProtectedUserSymKey = await this.cryptoService.makeUserSymKey(newMasterKey);
|
newProtectedUserKey = await this.cryptoService.makeUserKey(newMasterKey);
|
||||||
} else {
|
} else {
|
||||||
newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
|
newProtectedUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey);
|
||||||
newMasterKey
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserSymKey);
|
await this.performSubmitActions(newMasterPasswordHash, newMasterKey, newProtectedUserKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupSubmitActions(): Promise<boolean> {
|
async setupSubmitActions(): Promise<boolean> {
|
||||||
@ -117,7 +112,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
|
|||||||
async performSubmitActions(
|
async performSubmitActions(
|
||||||
masterPasswordHash: string,
|
masterPasswordHash: string,
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey: [UserSymKey, EncString]
|
userKey: [UserKey, EncString]
|
||||||
) {
|
) {
|
||||||
// Override in sub-class
|
// 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 { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
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 { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||||
|
|
||||||
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
|
import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
|
||||||
@ -153,41 +153,41 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
try {
|
try {
|
||||||
const kdf = await this.stateService.getKdfType();
|
const kdf = await this.stateService.getKdfType();
|
||||||
const kdfConfig = await this.stateService.getKdfConfig();
|
const kdfConfig = await this.stateService.getKdfConfig();
|
||||||
let userSymKeyPin: EncString;
|
let userKeyPin: EncString;
|
||||||
let oldPinProtected: EncString;
|
let oldPinProtected: EncString;
|
||||||
if (this.pinSet[0]) {
|
if (this.pinSet[0]) {
|
||||||
// MP on restart enabled
|
// MP on restart enabled
|
||||||
userSymKeyPin = await this.stateService.getUserSymKeyPinEphemeral();
|
userKeyPin = await this.stateService.getUserKeyPinEphemeral();
|
||||||
oldPinProtected = await this.stateService.getDecryptedPinProtected();
|
oldPinProtected = await this.stateService.getDecryptedPinProtected();
|
||||||
} else {
|
} else {
|
||||||
// MP on restart disabled
|
// MP on restart disabled
|
||||||
userSymKeyPin = await this.stateService.getUserSymKeyPin();
|
userKeyPin = await this.stateService.getUserKeyPin();
|
||||||
const oldEncryptedKey = await this.stateService.getEncryptedPinProtected();
|
const oldEncryptedKey = await this.stateService.getEncryptedPinProtected();
|
||||||
oldPinProtected = oldEncryptedKey ? new EncString(oldEncryptedKey) : undefined;
|
oldPinProtected = oldEncryptedKey ? new EncString(oldEncryptedKey) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let userSymKey: UserSymKey;
|
let userKey: UserKey;
|
||||||
if (oldPinProtected) {
|
if (oldPinProtected) {
|
||||||
userSymKey = await this.decryptAndMigrateOldPinKey(true, kdf, kdfConfig, oldPinProtected);
|
userKey = await this.decryptAndMigrateOldPinKey(true, kdf, kdfConfig, oldPinProtected);
|
||||||
} else {
|
} else {
|
||||||
userSymKey = await this.cryptoService.decryptUserSymKeyWithPin(
|
userKey = await this.cryptoService.decryptUserKeyWithPin(
|
||||||
this.pin,
|
this.pin,
|
||||||
this.email,
|
this.email,
|
||||||
kdf,
|
kdf,
|
||||||
kdfConfig,
|
kdfConfig,
|
||||||
userSymKeyPin
|
userKeyPin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const protectedPin = await this.stateService.getProtectedPin();
|
const protectedPin = await this.stateService.getProtectedPin();
|
||||||
const decryptedPin = await this.cryptoService.decryptToUtf8(
|
const decryptedPin = await this.cryptoService.decryptToUtf8(
|
||||||
new EncString(protectedPin),
|
new EncString(protectedPin),
|
||||||
userSymKey
|
userKey
|
||||||
);
|
);
|
||||||
failed = decryptedPin !== this.pin;
|
failed = decryptedPin !== this.pin;
|
||||||
|
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
await this.setKeyAndContinue(userSymKey);
|
await this.setKeyAndContinue(userKey);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
failed = true;
|
failed = true;
|
||||||
@ -275,22 +275,22 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
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
|
// 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]) {
|
if (this.pinSet[0]) {
|
||||||
const protectedPin = await this.stateService.getProtectedPin();
|
const protectedPin = await this.stateService.getProtectedPin();
|
||||||
const pin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), userKey);
|
const pin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), userKey);
|
||||||
const pinKey = await this.cryptoService.makePinKey(pin, this.email, kdf, kdfConfig);
|
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.cryptoService.encrypt(userKey.key, pinKey)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await this.setKeyAndContinue(userKey, true);
|
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.cryptoService.setUserKey(key);
|
||||||
await this.doContinue(evaluatePasswordAfterUnlock);
|
await this.doContinue(evaluatePasswordAfterUnlock);
|
||||||
}
|
}
|
||||||
@ -331,7 +331,7 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
private async load() {
|
private async load() {
|
||||||
this.pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
|
this.pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
|
||||||
|
|
||||||
let ephemeralPinSet = await this.stateService.getUserSymKeyPinEphemeral();
|
let ephemeralPinSet = await this.stateService.getUserKeyPinEphemeral();
|
||||||
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
|
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
|
||||||
this.pinLock = (this.pinSet[0] && !!ephemeralPinSet) || this.pinSet[1];
|
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.
|
* master key. Clears the old Pin key from state.
|
||||||
* @param masterPasswordOnRestart True if Master Password on Restart is enabled
|
* @param masterPasswordOnRestart True if Master Password on Restart is enabled
|
||||||
* @param kdf User's KdfType
|
* @param kdf User's KdfType
|
||||||
* @param kdfConfig User's KdfConfig
|
* @param kdfConfig User's KdfConfig
|
||||||
* @param oldPinProtected The old Pin key from state (retrieved from different
|
* @param oldPinProtected The old Pin key from state (retrieved from different
|
||||||
* places depending on if Master Password on Restart was enabled)
|
* places depending on if Master Password on Restart was enabled)
|
||||||
* @returns The user's symmetric key
|
* @returns The user key
|
||||||
*/
|
*/
|
||||||
private async decryptAndMigrateOldPinKey(
|
private async decryptAndMigrateOldPinKey(
|
||||||
masterPasswordOnRestart: boolean,
|
masterPasswordOnRestart: boolean,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfConfig: KdfConfig,
|
kdfConfig: KdfConfig,
|
||||||
oldPinProtected?: EncString
|
oldPinProtected?: EncString
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
// Decrypt
|
// Decrypt
|
||||||
const masterKey = await this.cryptoService.decryptMasterKeyWithPin(
|
const masterKey = await this.cryptoService.decryptMasterKeyWithPin(
|
||||||
this.pin,
|
this.pin,
|
||||||
@ -404,28 +404,28 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
kdfConfig,
|
kdfConfig,
|
||||||
oldPinProtected
|
oldPinProtected
|
||||||
);
|
);
|
||||||
const encUserSymKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
const encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||||
const userSymKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
|
||||||
masterKey,
|
masterKey,
|
||||||
new EncString(encUserSymKey)
|
new EncString(encUserKey)
|
||||||
);
|
);
|
||||||
// Migrate
|
// Migrate
|
||||||
const pinKey = await this.cryptoService.makePinKey(this.pin, this.email, kdf, kdfConfig);
|
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) {
|
if (masterPasswordOnRestart) {
|
||||||
await this.stateService.setDecryptedPinProtected(null);
|
await this.stateService.setDecryptedPinProtected(null);
|
||||||
await this.stateService.setUserSymKeyPinEphemeral(pinProtectedKey);
|
await this.stateService.setUserKeyPinEphemeral(pinProtectedKey);
|
||||||
} else {
|
} else {
|
||||||
await this.stateService.setEncryptedPinProtected(null);
|
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
|
// We previously only set the protected pin if MP on Restart was enabled
|
||||||
// now we set it regardless
|
// 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);
|
await this.stateService.setProtectedPin(encPin.encryptedString);
|
||||||
}
|
}
|
||||||
// This also clears the old Biometrics key since the new Biometrics key will
|
// 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);
|
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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import {
|
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
MasterKey,
|
|
||||||
UserSymKey,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
|
|
||||||
@ -100,7 +97,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
async performSubmitActions(
|
async performSubmitActions(
|
||||||
masterPasswordHash: string,
|
masterPasswordHash: string,
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey: [UserSymKey, EncString]
|
userKey: [UserKey, EncString]
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
// Create Request
|
// Create Request
|
||||||
@ -110,7 +107,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
request.newMasterPasswordHash = masterPasswordHash;
|
request.newMasterPasswordHash = masterPasswordHash;
|
||||||
request.key = userSymKey[1].encryptedString;
|
request.key = userKey[1].encryptedString;
|
||||||
|
|
||||||
// Update user's password
|
// Update user's password
|
||||||
this.apiService.postPassword(request);
|
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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import {
|
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
MasterKey,
|
|
||||||
UserSymKey,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
@ -128,16 +125,16 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
newMasterKey
|
newMasterKey
|
||||||
);
|
);
|
||||||
|
|
||||||
// Grab user's symmetric key
|
// Grab user key
|
||||||
const userKey = await this.cryptoService.getUserKeyFromMemory();
|
const userKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
|
|
||||||
// Encrypt user's symmetric key with new master key
|
// Encrypt user key with new master key
|
||||||
const newProtectedUserSymKey = await this.cryptoService.encryptUserSymKeyWithMasterKey(
|
const newProtectedUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(
|
||||||
newMasterKey,
|
newMasterKey,
|
||||||
userKey
|
userKey
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserSymKey);
|
await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserKey);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@ -146,15 +143,15 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
async performSubmitActions(
|
async performSubmitActions(
|
||||||
masterPasswordHash: string,
|
masterPasswordHash: string,
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey: [UserSymKey, EncString]
|
userKey: [UserKey, EncString]
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
switch (this.reason) {
|
switch (this.reason) {
|
||||||
case ForceResetPasswordReason.AdminForcePasswordReset:
|
case ForceResetPasswordReason.AdminForcePasswordReset:
|
||||||
this.formPromise = this.updateTempPassword(masterPasswordHash, userSymKey);
|
this.formPromise = this.updateTempPassword(masterPasswordHash, userKey);
|
||||||
break;
|
break;
|
||||||
case ForceResetPasswordReason.WeakMasterPassword:
|
case ForceResetPasswordReason.WeakMasterPassword:
|
||||||
this.formPromise = this.updatePassword(masterPasswordHash, userSymKey);
|
this.formPromise = this.updatePassword(masterPasswordHash, userKey);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,26 +173,23 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async updateTempPassword(
|
private async updateTempPassword(masterPasswordHash: string, userKey: [UserKey, EncString]) {
|
||||||
masterPasswordHash: string,
|
|
||||||
userSymKey: [UserSymKey, EncString]
|
|
||||||
) {
|
|
||||||
const request = new UpdateTempPasswordRequest();
|
const request = new UpdateTempPasswordRequest();
|
||||||
request.key = userSymKey[1].encryptedString;
|
request.key = userKey[1].encryptedString;
|
||||||
request.newMasterPasswordHash = masterPasswordHash;
|
request.newMasterPasswordHash = masterPasswordHash;
|
||||||
request.masterPasswordHint = this.hint;
|
request.masterPasswordHint = this.hint;
|
||||||
|
|
||||||
return this.apiService.putUpdateTempPassword(request);
|
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(
|
const request = await this.userVerificationService.buildRequest(
|
||||||
this.verification,
|
this.verification,
|
||||||
PasswordRequest
|
PasswordRequest
|
||||||
);
|
);
|
||||||
request.masterPasswordHint = this.hint;
|
request.masterPasswordHint = this.hint;
|
||||||
request.newMasterPasswordHash = newMasterPasswordHash;
|
request.newMasterPasswordHash = newMasterPasswordHash;
|
||||||
request.key = userSymKey[1].encryptedString;
|
request.key = userKey[1].encryptedString;
|
||||||
|
|
||||||
return this.apiService.postPassword(request);
|
return this.apiService.postPassword(request);
|
||||||
}
|
}
|
||||||
|
@ -272,15 +272,15 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
const kdf = DEFAULT_KDF_TYPE;
|
const kdf = DEFAULT_KDF_TYPE;
|
||||||
const kdfConfig = DEFAULT_KDF_CONFIG;
|
const kdfConfig = DEFAULT_KDF_CONFIG;
|
||||||
const key = await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig);
|
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 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(
|
const request = new RegisterRequest(
|
||||||
email,
|
email,
|
||||||
name,
|
name,
|
||||||
hashedPassword,
|
hashedPassword,
|
||||||
hint,
|
hint,
|
||||||
newUserSymKey[1].encryptedString,
|
newUserKey[1].encryptedString,
|
||||||
this.referenceData,
|
this.referenceData,
|
||||||
this.captchaToken,
|
this.captchaToken,
|
||||||
kdf,
|
kdf,
|
||||||
|
@ -18,10 +18,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import {
|
import { MasterKey, UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
MasterKey,
|
|
||||||
UserSymKey,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
|
|
||||||
@ -105,7 +102,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
async performSubmitActions(
|
async performSubmitActions(
|
||||||
masterPasswordHash: string,
|
masterPasswordHash: string,
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userKey: [UserSymKey, EncString]
|
userKey: [UserKey, EncString]
|
||||||
) {
|
) {
|
||||||
const newKeyPair = await this.cryptoService.makeKeyPair(userKey[0]);
|
const newKeyPair = await this.cryptoService.makeKeyPair(userKey[0]);
|
||||||
const request = new SetPasswordRequest(
|
const request = new SetPasswordRequest(
|
||||||
@ -134,7 +131,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
const userId = await this.stateService.getUserId();
|
const userId = await this.stateService.getUserId();
|
||||||
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
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 userKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
const encryptedUserKey = await this.cryptoService.rsaEncrypt(
|
const encryptedUserKey = await this.cryptoService.rsaEncrypt(
|
||||||
userKey.key,
|
userKey.key,
|
||||||
@ -176,7 +173,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
private async onSetPasswordSuccess(
|
private async onSetPasswordSuccess(
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userKey: [UserSymKey, EncString],
|
userKey: [UserKey, EncString],
|
||||||
keyPair: [string, EncString]
|
keyPair: [string, EncString]
|
||||||
) {
|
) {
|
||||||
await this.stateService.setKdfType(this.kdf);
|
await this.stateService.setKdfType(this.kdf);
|
||||||
|
@ -46,9 +46,9 @@ export class SetPinComponent implements OnInit {
|
|||||||
const encPin = await this.cryptoService.encrypt(this.pin, userKey);
|
const encPin = await this.cryptoService.encrypt(this.pin, userKey);
|
||||||
await this.stateService.setProtectedPin(encPin.encryptedString);
|
await this.stateService.setProtectedPin(encPin.encryptedString);
|
||||||
if (this.masterPassOnRestart) {
|
if (this.masterPassOnRestart) {
|
||||||
await this.stateService.setUserSymKeyPinEphemeral(pinProtectedKey);
|
await this.stateService.setUserKeyPinEphemeral(pinProtectedKey);
|
||||||
} else {
|
} else {
|
||||||
await this.stateService.setUserSymKeyPin(pinProtectedKey);
|
await this.stateService.setUserKeyPin(pinProtectedKey);
|
||||||
}
|
}
|
||||||
await this.cryptoService.clearOldPinKeys();
|
await this.cryptoService.clearOldPinKeys();
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ export abstract class DevicesApiServiceAbstraction {
|
|||||||
|
|
||||||
updateTrustedDeviceKeys: (
|
updateTrustedDeviceKeys: (
|
||||||
deviceIdentifier: string,
|
deviceIdentifier: string,
|
||||||
devicePublicKeyEncryptedUserSymKey: string,
|
devicePublicKeyEncryptedUserKey: string,
|
||||||
userSymKeyEncryptedDevicePublicKey: string,
|
userKeyEncryptedDevicePublicKey: string,
|
||||||
deviceKeyEncryptedDevicePrivateKey: string
|
deviceKeyEncryptedDevicePrivateKey: string
|
||||||
) => Promise<DeviceResponse>;
|
) => Promise<DeviceResponse>;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import { EncString } from "../../platform/models/domain/enc-string";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../../platform/models/domain/symmetric-crypto-key";
|
} from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
import {
|
import {
|
||||||
PasswordStrengthService,
|
PasswordStrengthService,
|
||||||
@ -43,7 +43,7 @@ const masterPassword = "password";
|
|||||||
const deviceId = Utils.newGuid();
|
const deviceId = Utils.newGuid();
|
||||||
const accessToken = "ACCESS_TOKEN";
|
const accessToken = "ACCESS_TOKEN";
|
||||||
const refreshToken = "REFRESH_TOKEN";
|
const refreshToken = "REFRESH_TOKEN";
|
||||||
const userSymKey = "USER_SYM_KEY";
|
const userKey = "USER_KEY";
|
||||||
const privateKey = "PRIVATE_KEY";
|
const privateKey = "PRIVATE_KEY";
|
||||||
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
||||||
const kdf = 0;
|
const kdf = 0;
|
||||||
@ -70,7 +70,7 @@ export function identityTokenResponseFactory(
|
|||||||
ForcePasswordReset: false,
|
ForcePasswordReset: false,
|
||||||
Kdf: kdf,
|
Kdf: kdf,
|
||||||
KdfIterations: kdfIterations,
|
KdfIterations: kdfIterations,
|
||||||
Key: userSymKey,
|
Key: userKey,
|
||||||
PrivateKey: privateKey,
|
PrivateKey: privateKey,
|
||||||
ResetMasterPassword: false,
|
ResetMasterPassword: false,
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
@ -135,15 +135,15 @@ describe("LogInStrategy", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("base class", () => {
|
describe("base class", () => {
|
||||||
const userSymKeyBytesLength = 64;
|
const userKeyBytesLength = 64;
|
||||||
const masterKeyBytesLength = 64;
|
const masterKeyBytesLength = 64;
|
||||||
let userSymKey: UserSymKey;
|
let userKey: UserKey;
|
||||||
let masterKey: MasterKey;
|
let masterKey: MasterKey;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
userSymKey = new SymmetricCryptoKey(
|
userKey = new SymmetricCryptoKey(
|
||||||
new Uint8Array(userSymKeyBytesLength).buffer as CsprngArray
|
new Uint8Array(userKeyBytesLength).buffer as CsprngArray
|
||||||
) as UserSymKey;
|
) as UserKey;
|
||||||
masterKey = new SymmetricCryptoKey(
|
masterKey = new SymmetricCryptoKey(
|
||||||
new Uint8Array(masterKeyBytesLength).buffer as CsprngArray
|
new Uint8Array(masterKeyBytesLength).buffer as CsprngArray
|
||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
@ -206,7 +206,7 @@ describe("LogInStrategy", () => {
|
|||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
const result = await passwordLogInStrategy.logIn(credentials);
|
const result = await passwordLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ describe("LogInStrategy", () => {
|
|||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
await passwordLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import { Utils } from "../../platform/misc/utils";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../../platform/models/domain/symmetric-crypto-key";
|
} from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
import {
|
import {
|
||||||
PasswordStrengthService,
|
PasswordStrengthService,
|
||||||
@ -134,19 +134,17 @@ describe("PasswordLogInStrategy", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("sets keys after a successful authentication", async () => {
|
it("sets keys after a successful authentication", async () => {
|
||||||
const userSymKey = new SymmetricCryptoKey(
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
new Uint8Array(64).buffer as CsprngArray
|
|
||||||
) as UserSymKey;
|
|
||||||
|
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
await passwordLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localHashedPassword);
|
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localHashedPassword);
|
||||||
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -147,11 +147,11 @@ export class PasswordLogInStrategy extends LogInStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
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();
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { Utils } from "../../platform/misc/utils";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../../platform/models/domain/symmetric-crypto-key";
|
} from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { TokenService } from "../abstractions/token.service";
|
import { TokenService } from "../abstractions/token.service";
|
||||||
@ -85,19 +85,17 @@ describe("SsoLogInStrategy", () => {
|
|||||||
|
|
||||||
it("sets keys after a successful authentication", async () => {
|
it("sets keys after a successful authentication", async () => {
|
||||||
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
||||||
const userSymKey = new SymmetricCryptoKey(
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
new Uint8Array(64).buffer as CsprngArray
|
|
||||||
) as UserSymKey;
|
|
||||||
|
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await passwordlessLoginStrategy.logIn(credentials);
|
await passwordlessLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localPasswordHash);
|
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localPasswordHash);
|
||||||
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -85,11 +85,11 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
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();
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { Utils } from "../../platform/misc/utils";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../../platform/models/domain/symmetric-crypto-key";
|
} from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { KeyConnectorService } from "../abstractions/key-connector.service";
|
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 () => {
|
it("decrypts and sets the user key if Key Connector is enabled", async () => {
|
||||||
const userSymKey = new SymmetricCryptoKey(
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
new Uint8Array(64).buffer as CsprngArray
|
|
||||||
) as UserSymKey;
|
|
||||||
const masterKey = new SymmetricCryptoKey(
|
const masterKey = new SymmetricCryptoKey(
|
||||||
new Uint8Array(64).buffer as CsprngArray
|
new Uint8Array(64).buffer as CsprngArray
|
||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await ssoLogInStrategy.logIn(credentials);
|
await ssoLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(cryptoService.decryptUserSymKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
|
expect(cryptoService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -83,14 +83,14 @@ export class SsoLogInStrategy extends LogInStrategy {
|
|||||||
const newSsoUser = tokenResponse.key == null;
|
const newSsoUser = tokenResponse.key == null;
|
||||||
|
|
||||||
if (!newSsoUser) {
|
if (!newSsoUser) {
|
||||||
await this.cryptoService.setUserSymKeyMasterKey(tokenResponse.key);
|
await this.cryptoService.setUserKeyMasterKey(tokenResponse.key);
|
||||||
|
|
||||||
if (tokenResponse.keyConnectorUrl != null) {
|
if (tokenResponse.keyConnectorUrl != null) {
|
||||||
const masterKey = await this.cryptoService.getMasterKey();
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
throw new Error("Master key not found");
|
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);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import { Utils } from "../../platform/misc/utils";
|
|||||||
import {
|
import {
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../../platform/models/domain/symmetric-crypto-key";
|
} from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { KeyConnectorService } from "../abstractions/key-connector.service";
|
import { KeyConnectorService } from "../abstractions/key-connector.service";
|
||||||
@ -107,14 +107,14 @@ describe("UserApiLogInStrategy", () => {
|
|||||||
expect(stateService.addAccount).toHaveBeenCalled();
|
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();
|
const tokenResponse = identityTokenResponseFactory();
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
await apiLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(cryptoService.setUserSymKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setUserKeyMasterKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -130,10 +130,8 @@ describe("UserApiLogInStrategy", () => {
|
|||||||
expect(keyConnectorService.getAndSetMasterKey).toHaveBeenCalledWith(keyConnectorUrl);
|
expect(keyConnectorService.getAndSetMasterKey).toHaveBeenCalledWith(keyConnectorUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("decrypts and sets the user symmetric key if Key Connector is enabled", async () => {
|
it("decrypts and sets the user key if Key Connector is enabled", async () => {
|
||||||
const userSymKey = new SymmetricCryptoKey(
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
new Uint8Array(64).buffer as CsprngArray
|
|
||||||
) as UserSymKey;
|
|
||||||
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
||||||
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
const tokenResponse = identityTokenResponseFactory();
|
||||||
@ -142,11 +140,11 @@ describe("UserApiLogInStrategy", () => {
|
|||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
environmentService.getKeyConnectorUrl.mockReturnValue(keyConnectorUrl);
|
environmentService.getKeyConnectorUrl.mockReturnValue(keyConnectorUrl);
|
||||||
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserSymKeyWithMasterKey.mockResolvedValue(userSymKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
await apiLogInStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(cryptoService.decryptUserSymKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
|
expect(cryptoService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userSymKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -64,12 +64,12 @@ export class UserApiLogInStrategy extends LogInStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
||||||
await this.cryptoService.setUserSymKeyMasterKey(response.key);
|
await this.cryptoService.setUserKeyMasterKey(response.key);
|
||||||
|
|
||||||
if (response.apiUseKeyConnector) {
|
if (response.apiUseKeyConnector) {
|
||||||
const masterKey = await this.cryptoService.getMasterKey();
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserSymKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
requestApproved: boolean
|
requestApproved: boolean
|
||||||
): Promise<AuthRequestResponse> {
|
): Promise<AuthRequestResponse> {
|
||||||
// TODO: This currently depends on always having the Master Key and MP Hash
|
// 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 pubKey = Utils.fromB64ToArray(key);
|
||||||
const masterKey = await this.cryptoService.getMasterKey();
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
|
@ -97,9 +97,9 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
|||||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
||||||
await this.cryptoService.setMasterKey(masterKey);
|
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.setUserKey(userKey[0]);
|
||||||
await this.cryptoService.setUserSymKeyMasterKey(userKey[1].encryptedString);
|
await this.cryptoService.setUserKeyMasterKey(userKey[1].encryptedString);
|
||||||
|
|
||||||
const [pubKey, privKey] = await this.cryptoService.makeKeyPair();
|
const [pubKey, privKey] = await this.cryptoService.makeKeyPair();
|
||||||
|
|
||||||
|
@ -10,90 +10,90 @@ import {
|
|||||||
OrgKey,
|
OrgKey,
|
||||||
PinKey,
|
PinKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../models/domain/symmetric-crypto-key";
|
} from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export abstract class CryptoService {
|
export abstract class CryptoService {
|
||||||
/**
|
/**
|
||||||
* Use for encryption/decryption of data in order to support legacy
|
* 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.
|
* if not it will return the master key.
|
||||||
*/
|
*/
|
||||||
getKeyForUserEncryption: (key?: SymmetricCryptoKey) => Promise<SymmetricCryptoKey>;
|
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
|
* 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
|
* @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,
|
* Gets the user key from memory and sets it again,
|
||||||
* kicking off a refresh of any additional keys that are needed.
|
* kicking off a refresh of any additional keys that are needed.
|
||||||
*/
|
*/
|
||||||
toggleKey: () => Promise<void>;
|
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
|
* @param keySuffix The desired version of the user's key to retrieve
|
||||||
* from storage if it is not available in memory
|
* from storage if it is not available in memory
|
||||||
* @param userId The desired user
|
* @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 keySuffix The desired version of the user's key to retrieve
|
||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
* @returns The user's symmetric key
|
* @returns The user key
|
||||||
*/
|
*/
|
||||||
getUserKeyFromStorage: (
|
getUserKeyFromStorage: (
|
||||||
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
||||||
userId?: string
|
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>;
|
hasUserKey: () => Promise<boolean>;
|
||||||
/**
|
/**
|
||||||
* @param userId The desired user
|
* @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>;
|
hasUserKeyInMemory: (userId?: string) => Promise<boolean>;
|
||||||
/**
|
/**
|
||||||
* @param keySuffix The desired version of the user's key to check
|
* @param keySuffix The desired version of the user's key to check
|
||||||
* @param userId The desired user
|
* @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: (
|
hasUserKeyStored: (
|
||||||
keySuffix?: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
keySuffix?: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
||||||
userId?: string
|
userId?: string
|
||||||
) => Promise<boolean>;
|
) => Promise<boolean>;
|
||||||
/**
|
/**
|
||||||
* Generates a new user symmetric key
|
* Generates a new user key
|
||||||
* @param masterKey The user's master 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,
|
* @param clearStoredKeys Clears all stored versions of the user keys as well,
|
||||||
* such as the biometrics key
|
* such as the biometrics key
|
||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
*/
|
*/
|
||||||
clearUserKey: (clearSecretStorage?: boolean, userId?: string) => Promise<void>;
|
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 keySuffix The desired version of the key to clear
|
||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
*/
|
*/
|
||||||
clearStoredUserKey: (keySuffix: KeySuffixOptions, userId?: string) => Promise<void>;
|
clearStoredUserKey: (keySuffix: KeySuffixOptions, userId?: string) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Stores the master key encrypted user symmetric key
|
* Stores the master key encrypted user key
|
||||||
* @param userSymKeyMasterKey The master key encrypted user symmetric key to set
|
* @param userKeyMasterKey The master key encrypted user key to set
|
||||||
* @param userId The desired user
|
* @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
|
* Sets the user's master key
|
||||||
* @param key The user's master key to set
|
* @param key The user's master key to set
|
||||||
@ -125,28 +125,28 @@ export abstract class CryptoService {
|
|||||||
*/
|
*/
|
||||||
clearMasterKey: (userId?: string) => Promise<void>;
|
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
|
* provided master key
|
||||||
* @param masterKey The user's master key
|
* @param masterKey The user's master key
|
||||||
* @param userSymKey The user's symmetric key
|
* @param userKey The user key
|
||||||
* @returns The user's symmetric key and the master key protected version of it
|
* @returns The user key and the master key protected version of it
|
||||||
*/
|
*/
|
||||||
encryptUserSymKeyWithMasterKey: (
|
encryptUserKeyWithMasterKey: (
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey?: UserSymKey
|
userKey?: UserKey
|
||||||
) => Promise<[UserSymKey, EncString]>;
|
) => 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 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
|
* @param userId The desired user
|
||||||
* @returns The user's symmetric key
|
* @returns The user key
|
||||||
*/
|
*/
|
||||||
decryptUserSymKeyWithMasterKey: (
|
decryptUserKeyWithMasterKey: (
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey?: EncString,
|
userKey?: EncString,
|
||||||
userId?: string
|
userId?: string
|
||||||
) => Promise<UserSymKey>;
|
) => Promise<UserKey>;
|
||||||
/**
|
/**
|
||||||
* Creates a master password hash from the user's master password. Can
|
* Creates a master password hash from the user's master password. Can
|
||||||
* be used for local authentication or for server authentication depending
|
* be used for local authentication or for server authentication depending
|
||||||
@ -265,7 +265,7 @@ export abstract class CryptoService {
|
|||||||
/**
|
/**
|
||||||
* Generates a new keypair
|
* Generates a new keypair
|
||||||
* @param key A key to encrypt the private key with. If not provided,
|
* @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]
|
* @returns A new keypair: [publicKey in Base64, encrypted privateKey]
|
||||||
*/
|
*/
|
||||||
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
|
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>;
|
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
|
* @param userId The desired user
|
||||||
*/
|
*/
|
||||||
clearPinProtectedKey: (userId?: string) => Promise<void>;
|
clearPinProtectedKey: (userId?: string) => Promise<void>;
|
||||||
@ -294,22 +294,22 @@ export abstract class CryptoService {
|
|||||||
*/
|
*/
|
||||||
clearOldPinKeys: (userId?: string) => Promise<void>;
|
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 pin The user's PIN
|
||||||
* @param salt The user's salt
|
* @param salt The user's salt
|
||||||
* @param kdf The user's KDF
|
* @param kdf The user's KDF
|
||||||
* @param kdfConfig The user's KDF config
|
* @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
|
* it will be retrieved from storage
|
||||||
* @returns The decrypted user's symmetric key
|
* @returns The decrypted user key
|
||||||
*/
|
*/
|
||||||
decryptUserSymKeyWithPin: (
|
decryptUserKeyWithPin: (
|
||||||
pin: string,
|
pin: string,
|
||||||
salt: string,
|
salt: string,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfConfig: KdfConfig,
|
kdfConfig: KdfConfig,
|
||||||
protectedKeyCs?: EncString
|
protectedKeyCs?: EncString
|
||||||
) => Promise<UserSymKey>;
|
) => Promise<UserKey>;
|
||||||
/**
|
/**
|
||||||
* @param keyMaterial The key material to derive the send key from
|
* @param keyMaterial The key material to derive the send key from
|
||||||
* @returns A new send key
|
* @returns A new send key
|
||||||
@ -337,7 +337,7 @@ export abstract class CryptoService {
|
|||||||
randomNumber: (min: number, max: number) => Promise<number>;
|
randomNumber: (min: number, max: number) => Promise<number>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Left for migration purposes. Use decryptUserSymKeyWithPin instead.
|
* @deprecated Left for migration purposes. Use decryptUserKeyWithPin instead.
|
||||||
*/
|
*/
|
||||||
decryptMasterKeyWithPin: (
|
decryptMasterKeyWithPin: (
|
||||||
pin: string,
|
pin: string,
|
||||||
|
@ -30,7 +30,7 @@ import {
|
|||||||
DeviceKey,
|
DeviceKey,
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../models/domain/symmetric-crypto-key";
|
} from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export abstract class StateService<T extends Account = Account> {
|
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>;
|
getConvertAccountToKeyConnector: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setConvertAccountToKeyConnector: (value: boolean, options?: StorageOptions) => Promise<void>;
|
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
|
* 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>;
|
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
|
* Gets the user's auto key
|
||||||
*/
|
*/
|
||||||
getUserSymKeyAuto: (options?: StorageOptions) => Promise<string>;
|
getUserKeyAuto: (options?: StorageOptions) => Promise<string>;
|
||||||
/**
|
/**
|
||||||
* Sets the user's auto key
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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>;
|
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>;
|
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
@ -154,23 +154,23 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
*/
|
*/
|
||||||
getCryptoMasterKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
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>;
|
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>;
|
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>;
|
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>;
|
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>;
|
setCryptoMasterKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
|
||||||
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
||||||
@ -192,11 +192,11 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
options?: StorageOptions
|
options?: StorageOptions
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
* @deprecated For migration purposes only, use getDecryptedUserSymKeyPin instead
|
* @deprecated For migration purposes only, use getDecryptedUserKeyPin instead
|
||||||
*/
|
*/
|
||||||
getDecryptedPinProtected: (options?: StorageOptions) => Promise<EncString>;
|
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>;
|
setDecryptedPinProtected: (value: EncString, options?: StorageOptions) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
@ -325,11 +325,11 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
options?: StorageOptions
|
options?: StorageOptions
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
* @deprecated For migration purposes only, use getEncryptedUserSymKeyPin instead
|
* @deprecated For migration purposes only, use getEncryptedUserKeyPin instead
|
||||||
*/
|
*/
|
||||||
getEncryptedPinProtected: (options?: StorageOptions) => Promise<string>;
|
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>;
|
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
@ -426,11 +426,11 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
getGeneratorOptions: (options?: StorageOptions) => Promise<any>;
|
getGeneratorOptions: (options?: StorageOptions) => Promise<any>;
|
||||||
setGeneratorOptions: (value: any, options?: StorageOptions) => Promise<void>;
|
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>;
|
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>;
|
setProtectedPin: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getProviders: (options?: StorageOptions) => Promise<{ [id: string]: ProviderData }>;
|
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 { ServerConfigData } from "../../models/data/server-config.data";
|
||||||
|
|
||||||
import { EncryptedString, EncString } from "./enc-string";
|
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> {
|
export class EncryptionPair<TEncrypted, TDecrypted> {
|
||||||
encrypted?: TEncrypted;
|
encrypted?: TEncrypted;
|
||||||
@ -99,11 +99,11 @@ export class AccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AccountKeys {
|
export class AccountKeys {
|
||||||
userSymKey?: UserSymKey;
|
userKey?: UserKey;
|
||||||
masterKey?: MasterKey;
|
masterKey?: MasterKey;
|
||||||
userSymKeyMasterKey?: string;
|
userKeyMasterKey?: string;
|
||||||
userSymKeyAuto?: string;
|
userKeyAuto?: string;
|
||||||
userSymKeyBiometric?: string;
|
userKeyBiometric?: string;
|
||||||
// deprecated keys
|
// deprecated keys
|
||||||
cryptoMasterKey?: SymmetricCryptoKey;
|
cryptoMasterKey?: SymmetricCryptoKey;
|
||||||
cryptoMasterKeyAuto?: string;
|
cryptoMasterKeyAuto?: string;
|
||||||
@ -141,7 +141,7 @@ export class AccountKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Object.assign(new AccountKeys(), {
|
return Object.assign(new AccountKeys(), {
|
||||||
userSymKey: SymmetricCryptoKey.fromJSON(obj?.userSymKey),
|
userKey: SymmetricCryptoKey.fromJSON(obj?.userKey),
|
||||||
masterKey: SymmetricCryptoKey.fromJSON(obj?.masterKey),
|
masterKey: SymmetricCryptoKey.fromJSON(obj?.masterKey),
|
||||||
cryptoMasterKey: SymmetricCryptoKey.fromJSON(obj?.cryptoMasterKey),
|
cryptoMasterKey: SymmetricCryptoKey.fromJSON(obj?.cryptoMasterKey),
|
||||||
cryptoSymmetricKey: EncryptionPair.fromJSON(
|
cryptoSymmetricKey: EncryptionPair.fromJSON(
|
||||||
@ -232,8 +232,8 @@ export class AccountSettings {
|
|||||||
passwordGenerationOptions?: any;
|
passwordGenerationOptions?: any;
|
||||||
usernameGenerationOptions?: any;
|
usernameGenerationOptions?: any;
|
||||||
generatorOptions?: any;
|
generatorOptions?: any;
|
||||||
userSymKeyPin?: EncryptedString;
|
userKeyPin?: EncryptedString;
|
||||||
userSymKeyPinEphemeral?: EncryptedString;
|
userKeyPinEphemeral?: EncryptedString;
|
||||||
protectedPin?: string;
|
protectedPin?: string;
|
||||||
pinProtected?: EncryptionPair<string, EncString> = new EncryptionPair<string, EncString>(); // Deprecated
|
pinProtected?: EncryptionPair<string, EncString> = new EncryptionPair<string, EncString>(); // Deprecated
|
||||||
settings?: AccountSettingsSettings; // TODO: Merge whatever is going on here into the AccountSettings model properly
|
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
|
// Setup all separate key types as opaque types
|
||||||
export type DeviceKey = Opaque<SymmetricCryptoKey, "DeviceKey">;
|
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 MasterKey = Opaque<SymmetricCryptoKey, "MasterKey">;
|
||||||
export type PinKey = Opaque<SymmetricCryptoKey, "PinKey">;
|
export type PinKey = Opaque<SymmetricCryptoKey, "PinKey">;
|
||||||
export type OrgKey = Opaque<SymmetricCryptoKey, "OrgKey">;
|
export type OrgKey = Opaque<SymmetricCryptoKey, "OrgKey">;
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
MasterKey,
|
MasterKey,
|
||||||
PinKey,
|
PinKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../models/domain/symmetric-crypto-key";
|
} from "../models/domain/symmetric-crypto-key";
|
||||||
import { CryptoService } from "../services/crypto.service";
|
import { CryptoService } from "../services/crypto.service";
|
||||||
|
|
||||||
@ -44,33 +44,33 @@ describe("cryptoService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("getKeyForUserDecryption", () => {
|
describe("getKeyForUserDecryption", () => {
|
||||||
let mockUserSymKey: UserSymKey;
|
let mockUserKey: UserKey;
|
||||||
let mockMasterKey: MasterKey;
|
let mockMasterKey: MasterKey;
|
||||||
let stateSvcGetUserSymKey: jest.SpyInstance;
|
let stateSvcGetUserKey: jest.SpyInstance;
|
||||||
let stateSvcGetMasterKey: jest.SpyInstance;
|
let stateSvcGetMasterKey: jest.SpyInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const mockRandomBytes = new Uint8Array(64).buffer as CsprngArray;
|
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;
|
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");
|
stateSvcGetMasterKey = jest.spyOn(stateService, "getMasterKey");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns the user's symmetric key if available", async () => {
|
it("returns the user key if available", async () => {
|
||||||
stateSvcGetUserSymKey.mockResolvedValue(mockUserSymKey);
|
stateSvcGetUserKey.mockResolvedValue(mockUserKey);
|
||||||
|
|
||||||
const encryptionKey = await cryptoService.getKeyForUserEncryption();
|
const encryptionKey = await cryptoService.getKeyForUserEncryption();
|
||||||
|
|
||||||
expect(stateSvcGetUserSymKey).toHaveBeenCalled();
|
expect(stateSvcGetUserKey).toHaveBeenCalled();
|
||||||
expect(stateSvcGetMasterKey).not.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 () => {
|
it("returns the user's master key when symmetric key is not available", async () => {
|
||||||
stateSvcGetUserSymKey.mockResolvedValue(null);
|
stateSvcGetUserKey.mockResolvedValue(null);
|
||||||
stateSvcGetMasterKey.mockResolvedValue(mockMasterKey);
|
stateSvcGetMasterKey.mockResolvedValue(mockMasterKey);
|
||||||
|
|
||||||
const encryptionKey = await cryptoService.getKeyForUserEncryption();
|
const encryptionKey = await cryptoService.getKeyForUserEncryption();
|
||||||
@ -82,32 +82,32 @@ describe("cryptoService", () => {
|
|||||||
|
|
||||||
describe("setUserKey", () => {
|
describe("setUserKey", () => {
|
||||||
const mockUserId = "example user id";
|
const mockUserId = "example user id";
|
||||||
let mockUserSymKey: UserSymKey;
|
let mockUserKey: UserKey;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const mockRandomBytes = new Uint8Array(64).buffer as CsprngArray;
|
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 () => {
|
it("saves an Auto key if needed", async () => {
|
||||||
stateService.getVaultTimeout.mockResolvedValue(null);
|
stateService.getVaultTimeout.mockResolvedValue(null);
|
||||||
|
|
||||||
await cryptoService.setUserKey(mockUserSymKey, mockUserId);
|
await cryptoService.setUserKey(mockUserKey, mockUserId);
|
||||||
|
|
||||||
expect(stateService.setUserSymKeyAuto).toHaveBeenCalled();
|
expect(stateService.setUserKeyAuto).toHaveBeenCalled();
|
||||||
expect(stateService.setUserSymKeyAuto).not.toHaveBeenCalledWith(null, { userId: mockUserId });
|
expect(stateService.setUserKeyAuto).not.toHaveBeenCalledWith(null, { userId: mockUserId });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("saves a Pin key if needed", async () => {
|
it("saves a Pin key if needed", async () => {
|
||||||
stateService.getUserSymKeyPinEphemeral.mockResolvedValue(null);
|
stateService.getUserKeyPinEphemeral.mockResolvedValue(null);
|
||||||
const cryptoSvcMakePinKey = jest.spyOn(cryptoService, "makePinKey");
|
const cryptoSvcMakePinKey = jest.spyOn(cryptoService, "makePinKey");
|
||||||
cryptoSvcMakePinKey.mockResolvedValue(
|
cryptoSvcMakePinKey.mockResolvedValue(
|
||||||
new SymmetricCryptoKey(new Uint8Array(64).buffer) as PinKey
|
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,
|
OrgKey,
|
||||||
PinKey,
|
PinKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../models/domain/symmetric-crypto-key";
|
} from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export class CryptoService implements CryptoServiceAbstraction {
|
export class CryptoService implements CryptoServiceAbstraction {
|
||||||
@ -54,8 +54,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return await this.getMasterKey();
|
return await this.getMasterKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setUserKey(key: UserSymKey, userId?: string): Promise<void> {
|
async setUserKey(key: UserKey, userId?: string): Promise<void> {
|
||||||
await this.stateService.setUserSymKey(key, { userId: userId });
|
await this.stateService.setUserKey(key, { userId: userId });
|
||||||
await this.storeAdditionalKeys(key, userId);
|
await this.storeAdditionalKeys(key, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +64,14 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
await this.setUserKey(key);
|
await this.setUserKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserKeyFromMemory(userId?: string): Promise<UserSymKey> {
|
async getUserKeyFromMemory(userId?: string): Promise<UserKey> {
|
||||||
return await this.stateService.getUserSymKey({ userId: userId });
|
return await this.stateService.getUserKey({ userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserKeyFromStorage(
|
async getUserKeyFromStorage(
|
||||||
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
keySuffix: KeySuffixOptions.Auto | KeySuffixOptions.Biometric,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
const userKey = await this.retrieveUserKeyFromStorage(keySuffix, userId);
|
const userKey = await this.retrieveUserKeyFromStorage(keySuffix, userId);
|
||||||
if (userKey != null) {
|
if (userKey != null) {
|
||||||
if (!(await this.validateUserKey(userKey))) {
|
if (!(await this.validateUserKey(userKey))) {
|
||||||
@ -94,7 +94,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async hasUserKeyInMemory(userId?: string): Promise<boolean> {
|
async hasUserKeyInMemory(userId?: string): Promise<boolean> {
|
||||||
return (await this.stateService.getUserSymKey({ userId: userId })) != null;
|
return (await this.stateService.getUserKey({ userId: userId })) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async hasUserKeyStored(
|
async hasUserKeyStored(
|
||||||
@ -103,23 +103,23 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||||
const oldKey = await this.stateService.hasCryptoMasterKeyBiometric({ userId: userId });
|
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;
|
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();
|
masterKey ||= await this.getMasterKey();
|
||||||
if (masterKey == null) {
|
if (masterKey == null) {
|
||||||
throw new Error("No Master Key found.");
|
throw new Error("No Master Key found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const newUserSymKey = await this.cryptoFunctionService.randomBytes(64);
|
const newUserKey = await this.cryptoFunctionService.randomBytes(64);
|
||||||
return this.buildProtectedSymmetricKey(masterKey, newUserSymKey);
|
return this.buildProtectedSymmetricKey(masterKey, newUserKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearUserKey(clearStoredKeys = true, userId?: string): Promise<void> {
|
async clearUserKey(clearStoredKeys = true, userId?: string): Promise<void> {
|
||||||
await this.stateService.setUserSymKey(null, { userId: userId });
|
await this.stateService.setUserKey(null, { userId: userId });
|
||||||
if (clearStoredKeys) {
|
if (clearStoredKeys) {
|
||||||
await this.clearAllStoredUserKeys(userId);
|
await this.clearAllStoredUserKeys(userId);
|
||||||
}
|
}
|
||||||
@ -128,19 +128,19 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
async clearStoredUserKey(keySuffix: KeySuffixOptions, userId?: string): Promise<void> {
|
async clearStoredUserKey(keySuffix: KeySuffixOptions, userId?: string): Promise<void> {
|
||||||
switch (keySuffix) {
|
switch (keySuffix) {
|
||||||
case KeySuffixOptions.Auto:
|
case KeySuffixOptions.Auto:
|
||||||
this.stateService.setUserSymKeyAuto(null, { userId: userId });
|
this.stateService.setUserKeyAuto(null, { userId: userId });
|
||||||
break;
|
break;
|
||||||
case KeySuffixOptions.Biometric:
|
case KeySuffixOptions.Biometric:
|
||||||
this.stateService.setUserSymKeyBiometric(null, { userId: userId });
|
this.stateService.setUserKeyBiometric(null, { userId: userId });
|
||||||
break;
|
break;
|
||||||
case KeySuffixOptions.Pin:
|
case KeySuffixOptions.Pin:
|
||||||
this.stateService.setUserSymKeyPinEphemeral(null, { userId: userId });
|
this.stateService.setUserKeyPinEphemeral(null, { userId: userId });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setUserSymKeyMasterKey(userSymKeyMasterKey: string, userId?: string): Promise<void> {
|
async setUserKeyMasterKey(userKeyMasterKey: string, userId?: string): Promise<void> {
|
||||||
await this.stateService.setUserSymKeyMasterKey(userSymKeyMasterKey, { userId: userId });
|
await this.stateService.setUserKeyMasterKey(userKeyMasterKey, { userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async setMasterKey(key: MasterKey, userId?: string): Promise<void> {
|
async setMasterKey(key: MasterKey, userId?: string): Promise<void> {
|
||||||
@ -166,40 +166,40 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
await this.stateService.setMasterKey(null, { userId: userId });
|
await this.stateService.setMasterKey(null, { userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async encryptUserSymKeyWithMasterKey(
|
async encryptUserKeyWithMasterKey(
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey?: UserSymKey
|
userKey?: UserKey
|
||||||
): Promise<[UserSymKey, EncString]> {
|
): Promise<[UserKey, EncString]> {
|
||||||
userSymKey ||= await this.getUserKeyFromMemory();
|
userKey ||= await this.getUserKeyFromMemory();
|
||||||
return this.buildProtectedSymmetricKey(masterKey, userSymKey.key);
|
return this.buildProtectedSymmetricKey(masterKey, userKey.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptUserSymKeyWithMasterKey(
|
async decryptUserKeyWithMasterKey(
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userSymKey?: EncString,
|
userKey?: EncString,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
masterKey ||= await this.getMasterKey();
|
masterKey ||= await this.getMasterKey();
|
||||||
if (masterKey == null) {
|
if (masterKey == null) {
|
||||||
throw new Error("No master key found.");
|
throw new Error("No master key found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userSymKey) {
|
if (!userKey) {
|
||||||
const userSymKeyMasterKey = await this.stateService.getUserSymKeyMasterKey({
|
const userKeyMasterKey = await this.stateService.getUserKeyMasterKey({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
});
|
});
|
||||||
if (userSymKeyMasterKey == null) {
|
if (userKeyMasterKey == null) {
|
||||||
throw new Error("No encrypted user key found.");
|
throw new Error("No encrypted user key found.");
|
||||||
}
|
}
|
||||||
userSymKey = new EncString(userSymKeyMasterKey);
|
userKey = new EncString(userKeyMasterKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decUserKey: ArrayBuffer;
|
let decUserKey: ArrayBuffer;
|
||||||
if (userSymKey.encryptionType === EncryptionType.AesCbc256_B64) {
|
if (userKey.encryptionType === EncryptionType.AesCbc256_B64) {
|
||||||
decUserKey = await this.decryptToBytes(userSymKey, masterKey);
|
decUserKey = await this.decryptToBytes(userKey, masterKey);
|
||||||
} else if (userSymKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) {
|
} else if (userKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) {
|
||||||
const newKey = await this.stretchKey(masterKey);
|
const newKey = await this.stretchKey(masterKey);
|
||||||
decUserKey = await this.decryptToBytes(userSymKey, newKey);
|
decUserKey = await this.decryptToBytes(userKey, newKey);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unsupported encryption type.");
|
throw new Error("Unsupported encryption type.");
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SymmetricCryptoKey(decUserKey) as UserSymKey;
|
return new SymmetricCryptoKey(decUserKey) as UserKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
async hashPassword(password: string, key: MasterKey, hashPurpose?: HashPurpose): Promise<string> {
|
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> {
|
async clearPinProtectedKey(userId?: string): Promise<void> {
|
||||||
await this.stateService.setUserSymKeyPin(null, { userId: userId });
|
await this.stateService.setUserKeyPin(null, { userId: userId });
|
||||||
await this.clearOldPinKeys(userId);
|
await this.clearOldPinKeys(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,20 +512,20 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
await this.stateService.setDecryptedPinProtected(null, { userId: userId });
|
await this.stateService.setDecryptedPinProtected(null, { userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptUserSymKeyWithPin(
|
async decryptUserKeyWithPin(
|
||||||
pin: string,
|
pin: string,
|
||||||
salt: string,
|
salt: string,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfConfig: KdfConfig,
|
kdfConfig: KdfConfig,
|
||||||
pinProtectedUserSymKey?: EncString
|
pinProtectedUserKey?: EncString
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
pinProtectedUserSymKey ||= await this.stateService.getUserSymKeyPin();
|
pinProtectedUserKey ||= await this.stateService.getUserKeyPin();
|
||||||
if (!pinProtectedUserSymKey) {
|
if (!pinProtectedUserKey) {
|
||||||
throw new Error("No PIN protected key found.");
|
throw new Error("No PIN protected key found.");
|
||||||
}
|
}
|
||||||
const pinKey = await this.makePinKey(pin, salt, kdf, kdfConfig);
|
const pinKey = await this.makePinKey(pin, salt, kdf, kdfConfig);
|
||||||
const userSymKey = await this.decryptToBytes(pinProtectedUserSymKey, pinKey);
|
const userKey = await this.decryptToBytes(pinProtectedUserKey, pinKey);
|
||||||
return new SymmetricCryptoKey(userSymKey) as UserSymKey;
|
return new SymmetricCryptoKey(userKey) as UserKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptMasterKeyWithPin(
|
async decryptMasterKeyWithPin(
|
||||||
@ -669,7 +669,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
|
|
||||||
// ---HELPERS---
|
// ---HELPERS---
|
||||||
|
|
||||||
protected async validateUserKey(key?: UserSymKey): Promise<boolean> {
|
protected async validateUserKey(key?: UserKey): Promise<boolean> {
|
||||||
key ||= await this.getUserKeyFromMemory();
|
key ||= await this.getUserKeyFromMemory();
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -692,27 +692,27 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerates any additional keys if needed. Useful to make sure
|
* Regenerates any additional keys if needed. Useful to make sure
|
||||||
* other keys stay in sync when the user's symmetric key has been rotated.
|
* other keys stay in sync when the user key has been rotated.
|
||||||
* @param key The user's symmetric key
|
* @param key The user key
|
||||||
* @param userId The desired user
|
* @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);
|
const storeAuto = await this.shouldStoreKey(KeySuffixOptions.Auto, userId);
|
||||||
if (storeAuto) {
|
if (storeAuto) {
|
||||||
await this.stateService.setUserSymKeyAuto(key.keyB64, { userId: userId });
|
await this.stateService.setUserKeyAuto(key.keyB64, { userId: userId });
|
||||||
} else {
|
} else {
|
||||||
await this.stateService.setUserSymKeyAuto(null, { userId: userId });
|
await this.stateService.setUserKeyAuto(null, { userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
const storePin = await this.shouldStoreKey(KeySuffixOptions.Pin, userId);
|
const storePin = await this.shouldStoreKey(KeySuffixOptions.Pin, userId);
|
||||||
if (storePin) {
|
if (storePin) {
|
||||||
await this.storePinKey(key);
|
await this.storePinKey(key);
|
||||||
} else {
|
} 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 email = await this.stateService.getEmail();
|
||||||
const kdf = await this.stateService.getKdfType();
|
const kdf = await this.stateService.getKdfType();
|
||||||
const kdfConfig = await this.stateService.getKdfConfig();
|
const kdfConfig = await this.stateService.getKdfConfig();
|
||||||
@ -721,7 +721,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
key
|
key
|
||||||
);
|
);
|
||||||
const pinKey = await this.makePinKey(pin, email, kdf, kdfConfig);
|
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) {
|
protected async shouldStoreKey(keySuffix: KeySuffixOptions, userId?: string) {
|
||||||
@ -741,10 +741,10 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
const protectedPin = await this.stateService.getProtectedPin({ userId: userId });
|
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
|
// This could cause a possible timing issue. Need to make sure the ephemeral key is set before
|
||||||
// we set our user key
|
// we set our user key
|
||||||
const userSymKeyPinEphemeral = await this.stateService.getUserSymKeyPinEphemeral({
|
const userKeyPinEphemeral = await this.stateService.getUserKeyPinEphemeral({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
});
|
});
|
||||||
shouldStoreKey = !!protectedPin && !userSymKeyPinEphemeral;
|
shouldStoreKey = !!protectedPin && !userKeyPinEphemeral;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -754,12 +754,12 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
protected async retrieveUserKeyFromStorage(
|
protected async retrieveUserKeyFromStorage(
|
||||||
keySuffix: KeySuffixOptions,
|
keySuffix: KeySuffixOptions,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<UserSymKey> {
|
): Promise<UserKey> {
|
||||||
if (keySuffix === KeySuffixOptions.Auto) {
|
if (keySuffix === KeySuffixOptions.Auto) {
|
||||||
await this.migrateAutoKeyIfNeeded(userId);
|
await this.migrateAutoKeyIfNeeded(userId);
|
||||||
const userKey = await this.stateService.getUserSymKeyAuto({ userId: userId });
|
const userKey = await this.stateService.getUserKeyAuto({ userId: userId });
|
||||||
if (userKey) {
|
if (userKey) {
|
||||||
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserSymKey;
|
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey).buffer) as UserKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -772,12 +772,12 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
const masterKey = new SymmetricCryptoKey(
|
const masterKey = new SymmetricCryptoKey(
|
||||||
Utils.fromB64ToArray(oldAutoKey).buffer
|
Utils.fromB64ToArray(oldAutoKey).buffer
|
||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
const userSymKey = await this.decryptUserSymKeyWithMasterKey(
|
const userKey = await this.decryptUserKeyWithMasterKey(
|
||||||
masterKey,
|
masterKey,
|
||||||
new EncString(await this.stateService.getEncryptedCryptoSymmetricKey())
|
new EncString(await this.stateService.getEncryptedCryptoSymmetricKey())
|
||||||
);
|
);
|
||||||
// migrate
|
// migrate
|
||||||
await this.stateService.setUserSymKeyAuto(userSymKey.keyB64, { userId: userId });
|
await this.stateService.setUserKeyAuto(userKey.keyB64, { userId: userId });
|
||||||
await this.stateService.setCryptoMasterKeyAuto(null, { 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> {
|
private async clearAllStoredUserKeys(userId?: string): Promise<void> {
|
||||||
await this.stateService.setUserSymKeyAuto(null, { userId: userId });
|
await this.stateService.setUserKeyAuto(null, { userId: userId });
|
||||||
await this.stateService.setUserSymKeyBiometric(null, { userId: userId });
|
await this.stateService.setUserKeyBiometric(null, { userId: userId });
|
||||||
await this.stateService.setUserSymKeyPinEphemeral(null, { userId: userId });
|
await this.stateService.setUserKeyPinEphemeral(null, { userId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async makeKey(
|
async makeKey(
|
||||||
|
@ -54,7 +54,7 @@ import {
|
|||||||
DeviceKey,
|
DeviceKey,
|
||||||
MasterKey,
|
MasterKey,
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../models/domain/symmetric-crypto-key";
|
} from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
const keys = {
|
const keys = {
|
||||||
@ -69,7 +69,7 @@ const keys = {
|
|||||||
const partialKeys = {
|
const partialKeys = {
|
||||||
userAutoKey: "_user_auto",
|
userAutoKey: "_user_auto",
|
||||||
userBiometricKey: "_user_biometric",
|
userBiometricKey: "_user_biometric",
|
||||||
userSymKey: "_user_sym",
|
userKey: "_user_key",
|
||||||
|
|
||||||
autoKey: "_masterkey_auto",
|
autoKey: "_masterkey_auto",
|
||||||
biometricKey: "_masterkey_biometric",
|
biometricKey: "_masterkey_biometric",
|
||||||
@ -122,7 +122,7 @@ export class StateService<
|
|||||||
// FIXME: This should be refactored into AuthService or a similar service,
|
// FIXME: This should be refactored into AuthService or a similar service,
|
||||||
// as checking for the existence of the crypto key is a low level
|
// as checking for the existence of the crypto key is a low level
|
||||||
// implementation detail.
|
// implementation detail.
|
||||||
this.activeAccountUnlockedSubject.next((await this.getUserSymKey()) != null);
|
this.activeAccountUnlockedSubject.next((await this.getUserKey()) != null);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe();
|
.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(
|
const account = await this.getAccount(
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
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(
|
const account = await this.getAccount(
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||||
);
|
);
|
||||||
account.keys.userSymKey = value;
|
account.keys.userKey = value;
|
||||||
await this.saveAccount(
|
await this.saveAccount(
|
||||||
account,
|
account,
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||||
@ -619,21 +619,21 @@ export class StateService<
|
|||||||
* The master key encrypted User symmetric key, saved on every auth
|
* The master key encrypted User symmetric key, saved on every auth
|
||||||
* so we can unlock with MP offline
|
* so we can unlock with MP offline
|
||||||
*/
|
*/
|
||||||
async getUserSymKeyMasterKey(options?: StorageOptions): Promise<string> {
|
async getUserKeyMasterKey(options?: StorageOptions): Promise<string> {
|
||||||
return (
|
return (
|
||||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||||
)?.keys.userSymKeyMasterKey;
|
)?.keys.userKeyMasterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The master key encrypted User symmetric key, saved on every auth
|
* The master key encrypted User symmetric key, saved on every auth
|
||||||
* so we can unlock with MP offline
|
* 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(
|
const account = await this.getAccount(
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||||
);
|
);
|
||||||
account.keys.userSymKeyMasterKey = value;
|
account.keys.userKeyMasterKey = value;
|
||||||
await this.saveAccount(
|
await this.saveAccount(
|
||||||
account,
|
account,
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
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(
|
options = this.reconcileOptions(
|
||||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||||
await this.defaultSecureStorageOptions()
|
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(
|
options = this.reconcileOptions(
|
||||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||||
await this.defaultSecureStorageOptions()
|
await this.defaultSecureStorageOptions()
|
||||||
@ -674,7 +674,7 @@ export class StateService<
|
|||||||
/**
|
/**
|
||||||
* User's encrypted symmetric key when using biometrics
|
* User's encrypted symmetric key when using biometrics
|
||||||
*/
|
*/
|
||||||
async getUserSymKeyBiometric(options?: StorageOptions): Promise<string> {
|
async getUserKeyBiometric(options?: StorageOptions): Promise<string> {
|
||||||
options = this.reconcileOptions(
|
options = this.reconcileOptions(
|
||||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||||
await this.defaultSecureStorageOptions()
|
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(
|
options = this.reconcileOptions(
|
||||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||||
await this.defaultSecureStorageOptions()
|
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(
|
options = this.reconcileOptions(
|
||||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||||
await this.defaultSecureStorageOptions()
|
await this.defaultSecureStorageOptions()
|
||||||
@ -713,36 +713,36 @@ export class StateService<
|
|||||||
await this.saveSecureStorageKey(partialKeys.userBiometricKey, value, options);
|
await this.saveSecureStorageKey(partialKeys.userBiometricKey, value, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserSymKeyPin(options?: StorageOptions): Promise<EncString> {
|
async getUserKeyPin(options?: StorageOptions): Promise<EncString> {
|
||||||
return EncString.fromJSON(
|
return EncString.fromJSON(
|
||||||
(await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
(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(
|
const account = await this.getAccount(
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||||
);
|
);
|
||||||
account.settings.userSymKeyPin = value?.encryptedString;
|
account.settings.userKeyPin = value?.encryptedString;
|
||||||
await this.saveAccount(
|
await this.saveAccount(
|
||||||
account,
|
account,
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserSymKeyPinEphemeral(options?: StorageOptions): Promise<EncString> {
|
async getUserKeyPinEphemeral(options?: StorageOptions): Promise<EncString> {
|
||||||
return EncString.fromJSON(
|
return EncString.fromJSON(
|
||||||
(await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions())))
|
(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(
|
const account = await this.getAccount(
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||||
);
|
);
|
||||||
account.settings.userSymKeyPinEphemeral = value?.encryptedString;
|
account.settings.userKeyPinEphemeral = value?.encryptedString;
|
||||||
await this.saveAccount(
|
await this.saveAccount(
|
||||||
account,
|
account,
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
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> {
|
async getCryptoMasterKeyAuto(options?: StorageOptions): Promise<string> {
|
||||||
options = this.reconcileOptions(
|
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> {
|
async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise<void> {
|
||||||
options = this.reconcileOptions(
|
options = this.reconcileOptions(
|
||||||
@ -806,7 +806,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKeyBiometric instead
|
* @deprecated Use UserKeyBiometric instead
|
||||||
*/
|
*/
|
||||||
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<string> {
|
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<string> {
|
||||||
options = this.reconcileOptions(
|
options = this.reconcileOptions(
|
||||||
@ -823,7 +823,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKeyBiometric instead
|
* @deprecated Use UserKeyBiometric instead
|
||||||
*/
|
*/
|
||||||
async hasCryptoMasterKeyBiometric(options?: StorageOptions): Promise<boolean> {
|
async hasCryptoMasterKeyBiometric(options?: StorageOptions): Promise<boolean> {
|
||||||
options = this.reconcileOptions(
|
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> {
|
async setCryptoMasterKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
|
||||||
options = this.reconcileOptions(
|
options = this.reconcileOptions(
|
||||||
@ -890,7 +890,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKey instead
|
* @deprecated Use UserKey instead
|
||||||
*/
|
*/
|
||||||
async getDecryptedCryptoSymmetricKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
async getDecryptedCryptoSymmetricKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||||
const account = await this.getAccount(
|
const account = await this.getAccount(
|
||||||
@ -900,7 +900,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKey instead
|
* @deprecated Use UserKey instead
|
||||||
*/
|
*/
|
||||||
async setDecryptedCryptoSymmetricKey(
|
async setDecryptedCryptoSymmetricKey(
|
||||||
value: SymmetricCryptoKey,
|
value: SymmetricCryptoKey,
|
||||||
@ -1601,7 +1601,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKey instead
|
* @deprecated Use UserKey instead
|
||||||
*/
|
*/
|
||||||
async getEncryptedCryptoSymmetricKey(options?: StorageOptions): Promise<string> {
|
async getEncryptedCryptoSymmetricKey(options?: StorageOptions): Promise<string> {
|
||||||
return (
|
return (
|
||||||
@ -1610,7 +1610,7 @@ export class StateService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use UserSymKey instead
|
* @deprecated Use UserKey instead
|
||||||
*/
|
*/
|
||||||
async setEncryptedCryptoSymmetricKey(value: string, options?: StorageOptions): Promise<void> {
|
async setEncryptedCryptoSymmetricKey(value: string, options?: StorageOptions): Promise<void> {
|
||||||
const account = await this.getAccount(
|
const account = await this.getAccount(
|
||||||
@ -3018,8 +3018,8 @@ export class StateService<
|
|||||||
|
|
||||||
protected async removeAccountFromSecureStorage(userId: string = null): Promise<void> {
|
protected async removeAccountFromSecureStorage(userId: string = null): Promise<void> {
|
||||||
userId = userId ?? (await this.state())?.activeUserId;
|
userId = userId ?? (await this.state())?.activeUserId;
|
||||||
await this.setUserSymKeyAuto(null, { userId: userId });
|
await this.setUserKeyAuto(null, { userId: userId });
|
||||||
await this.setUserSymKeyBiometric(null, { userId: userId });
|
await this.setUserKeyBiometric(null, { userId: userId });
|
||||||
await this.setCryptoMasterKeyAuto(null, { userId: userId });
|
await this.setCryptoMasterKeyAuto(null, { userId: userId });
|
||||||
await this.setCryptoMasterKeyBiometric(null, { userId: userId });
|
await this.setCryptoMasterKeyBiometric(null, { userId: userId });
|
||||||
await this.setCryptoMasterKeyB64(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
|
// 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) {
|
if (ephemeralPin != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { StateService } from "../platform/abstractions/state.service";
|
|||||||
import {
|
import {
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
DeviceKey,
|
DeviceKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../platform/models/domain/symmetric-crypto-key";
|
} from "../platform/models/domain/symmetric-crypto-key";
|
||||||
import { CsprngArray } from "../types/csprng";
|
import { CsprngArray } from "../types/csprng";
|
||||||
|
|
||||||
@ -24,11 +24,11 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async trustDevice(): Promise<DeviceResponse> {
|
async trustDevice(): Promise<DeviceResponse> {
|
||||||
// Attempt to get user symmetric key
|
// Attempt to get user key
|
||||||
const userSymKey: UserSymKey = await this.cryptoService.getUserKeyFromMemory();
|
const userKey: UserKey = await this.cryptoService.getUserKeyFromMemory();
|
||||||
|
|
||||||
// If user symmetric key is not found, throw error
|
// If user key is not found, throw error
|
||||||
if (!userSymKey) {
|
if (!userKey) {
|
||||||
throw new Error("User symmetric key not found");
|
throw new Error("User symmetric key not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,15 +41,15 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
devicePublicKeyEncryptedUserSymKey,
|
devicePublicKeyEncryptedUserKey,
|
||||||
userSymKeyEncryptedDevicePublicKey,
|
userKeyEncryptedDevicePublicKey,
|
||||||
deviceKeyEncryptedDevicePrivateKey,
|
deviceKeyEncryptedDevicePrivateKey,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
// Encrypt user symmetric key with the DevicePublicKey
|
// Encrypt user key with the DevicePublicKey
|
||||||
this.cryptoService.rsaEncrypt(userSymKey.encKey, devicePublicKey),
|
this.cryptoService.rsaEncrypt(userKey.encKey, devicePublicKey),
|
||||||
|
|
||||||
// Encrypt devicePublicKey with user symmetric key
|
// Encrypt devicePublicKey with user key
|
||||||
this.encryptService.encrypt(devicePublicKey, userSymKey),
|
this.encryptService.encrypt(devicePublicKey, userKey),
|
||||||
|
|
||||||
// Encrypt devicePrivateKey with deviceKey
|
// Encrypt devicePrivateKey with deviceKey
|
||||||
this.encryptService.encrypt(devicePrivateKey, deviceKey),
|
this.encryptService.encrypt(devicePrivateKey, deviceKey),
|
||||||
@ -59,8 +59,8 @@ export class DeviceCryptoService implements DeviceCryptoServiceAbstraction {
|
|||||||
const deviceIdentifier = await this.appIdService.getAppId();
|
const deviceIdentifier = await this.appIdService.getAppId();
|
||||||
return this.devicesApiService.updateTrustedDeviceKeys(
|
return this.devicesApiService.updateTrustedDeviceKeys(
|
||||||
deviceIdentifier,
|
deviceIdentifier,
|
||||||
devicePublicKeyEncryptedUserSymKey.encryptedString,
|
devicePublicKeyEncryptedUserKey.encryptedString,
|
||||||
userSymKeyEncryptedDevicePublicKey.encryptedString,
|
userKeyEncryptedDevicePublicKey.encryptedString,
|
||||||
deviceKeyEncryptedDevicePrivateKey.encryptedString
|
deviceKeyEncryptedDevicePrivateKey.encryptedString
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { EncString } from "../platform/models/domain/enc-string";
|
|||||||
import {
|
import {
|
||||||
SymmetricCryptoKey,
|
SymmetricCryptoKey,
|
||||||
DeviceKey,
|
DeviceKey,
|
||||||
UserSymKey,
|
UserKey,
|
||||||
} from "../platform/models/domain/symmetric-crypto-key";
|
} from "../platform/models/domain/symmetric-crypto-key";
|
||||||
import { CryptoService } from "../platform/services/crypto.service";
|
import { CryptoService } from "../platform/services/crypto.service";
|
||||||
import { CsprngArray } from "../types/csprng";
|
import { CsprngArray } from "../types/csprng";
|
||||||
@ -51,7 +51,7 @@ describe("deviceCryptoService", () => {
|
|||||||
|
|
||||||
describe("Trusted Device Encryption", () => {
|
describe("Trusted Device Encryption", () => {
|
||||||
const deviceKeyBytesLength = 64;
|
const deviceKeyBytesLength = 64;
|
||||||
const userSymKeyBytesLength = 64;
|
const userKeyBytesLength = 64;
|
||||||
|
|
||||||
describe("getDeviceKey", () => {
|
describe("getDeviceKey", () => {
|
||||||
let mockRandomBytes: CsprngArray;
|
let mockRandomBytes: CsprngArray;
|
||||||
@ -128,15 +128,15 @@ describe("deviceCryptoService", () => {
|
|||||||
let mockDeviceKeyRandomBytes: CsprngArray;
|
let mockDeviceKeyRandomBytes: CsprngArray;
|
||||||
let mockDeviceKey: DeviceKey;
|
let mockDeviceKey: DeviceKey;
|
||||||
|
|
||||||
let mockUserSymKeyRandomBytes: CsprngArray;
|
let mockUserKeyRandomBytes: CsprngArray;
|
||||||
let mockUserSymKey: UserSymKey;
|
let mockUserKey: UserKey;
|
||||||
|
|
||||||
const deviceRsaKeyLength = 2048;
|
const deviceRsaKeyLength = 2048;
|
||||||
let mockDeviceRsaKeyPair: [ArrayBuffer, ArrayBuffer];
|
let mockDeviceRsaKeyPair: [ArrayBuffer, ArrayBuffer];
|
||||||
let mockDevicePrivateKey: ArrayBuffer;
|
let mockDevicePrivateKey: ArrayBuffer;
|
||||||
let mockDevicePublicKey: ArrayBuffer;
|
let mockDevicePublicKey: ArrayBuffer;
|
||||||
let mockDevicePublicKeyEncryptedUserSymKey: EncString;
|
let mockDevicePublicKeyEncryptedUserKey: EncString;
|
||||||
let mockUserSymKeyEncryptedDevicePublicKey: EncString;
|
let mockUserKeyEncryptedDevicePublicKey: EncString;
|
||||||
let mockDeviceKeyEncryptedDevicePrivateKey: EncString;
|
let mockDeviceKeyEncryptedDevicePrivateKey: EncString;
|
||||||
|
|
||||||
const mockDeviceResponse: DeviceResponse = new DeviceResponse({
|
const mockDeviceResponse: DeviceResponse = new DeviceResponse({
|
||||||
@ -163,8 +163,8 @@ describe("deviceCryptoService", () => {
|
|||||||
mockDeviceKeyRandomBytes = new Uint8Array(deviceKeyBytesLength).buffer as CsprngArray;
|
mockDeviceKeyRandomBytes = new Uint8Array(deviceKeyBytesLength).buffer as CsprngArray;
|
||||||
mockDeviceKey = new SymmetricCryptoKey(mockDeviceKeyRandomBytes) as DeviceKey;
|
mockDeviceKey = new SymmetricCryptoKey(mockDeviceKeyRandomBytes) as DeviceKey;
|
||||||
|
|
||||||
mockUserSymKeyRandomBytes = new Uint8Array(userSymKeyBytesLength).buffer as CsprngArray;
|
mockUserKeyRandomBytes = new Uint8Array(userKeyBytesLength).buffer as CsprngArray;
|
||||||
mockUserSymKey = new SymmetricCryptoKey(mockUserSymKeyRandomBytes) as UserSymKey;
|
mockUserKey = new SymmetricCryptoKey(mockUserKeyRandomBytes) as UserKey;
|
||||||
|
|
||||||
mockDeviceRsaKeyPair = [
|
mockDeviceRsaKeyPair = [
|
||||||
new ArrayBuffer(deviceRsaKeyLength),
|
new ArrayBuffer(deviceRsaKeyLength),
|
||||||
@ -174,14 +174,14 @@ describe("deviceCryptoService", () => {
|
|||||||
mockDevicePublicKey = mockDeviceRsaKeyPair[0];
|
mockDevicePublicKey = mockDeviceRsaKeyPair[0];
|
||||||
mockDevicePrivateKey = mockDeviceRsaKeyPair[1];
|
mockDevicePrivateKey = mockDeviceRsaKeyPair[1];
|
||||||
|
|
||||||
mockDevicePublicKeyEncryptedUserSymKey = new EncString(
|
mockDevicePublicKeyEncryptedUserKey = new EncString(
|
||||||
EncryptionType.Rsa2048_OaepSha1_B64,
|
EncryptionType.Rsa2048_OaepSha1_B64,
|
||||||
"mockDevicePublicKeyEncryptedUserSymKey"
|
"mockDevicePublicKeyEncryptedUserKey"
|
||||||
);
|
);
|
||||||
|
|
||||||
mockUserSymKeyEncryptedDevicePublicKey = new EncString(
|
mockUserKeyEncryptedDevicePublicKey = new EncString(
|
||||||
EncryptionType.AesCbc256_HmacSha256_B64,
|
EncryptionType.AesCbc256_HmacSha256_B64,
|
||||||
"mockUserSymKeyEncryptedDevicePublicKey"
|
"mockUserKeyEncryptedDevicePublicKey"
|
||||||
);
|
);
|
||||||
|
|
||||||
mockDeviceKeyEncryptedDevicePrivateKey = new EncString(
|
mockDeviceKeyEncryptedDevicePrivateKey = new EncString(
|
||||||
@ -200,17 +200,17 @@ describe("deviceCryptoService", () => {
|
|||||||
|
|
||||||
cryptoSvcGetUserKeyFromMemorySpy = jest
|
cryptoSvcGetUserKeyFromMemorySpy = jest
|
||||||
.spyOn(cryptoService, "getUserKeyFromMemory")
|
.spyOn(cryptoService, "getUserKeyFromMemory")
|
||||||
.mockResolvedValue(mockUserSymKey);
|
.mockResolvedValue(mockUserKey);
|
||||||
|
|
||||||
cryptoSvcRsaEncryptSpy = jest
|
cryptoSvcRsaEncryptSpy = jest
|
||||||
.spyOn(cryptoService, "rsaEncrypt")
|
.spyOn(cryptoService, "rsaEncrypt")
|
||||||
.mockResolvedValue(mockDevicePublicKeyEncryptedUserSymKey);
|
.mockResolvedValue(mockDevicePublicKeyEncryptedUserKey);
|
||||||
|
|
||||||
encryptServiceEncryptSpy = jest
|
encryptServiceEncryptSpy = jest
|
||||||
.spyOn(encryptService, "encrypt")
|
.spyOn(encryptService, "encrypt")
|
||||||
.mockImplementation((plainValue, key) => {
|
.mockImplementation((plainValue, key) => {
|
||||||
if (plainValue === mockDevicePublicKey && key === mockUserSymKey) {
|
if (plainValue === mockDevicePublicKey && key === mockUserKey) {
|
||||||
return Promise.resolve(mockUserSymKeyEncryptedDevicePublicKey);
|
return Promise.resolve(mockUserKeyEncryptedDevicePublicKey);
|
||||||
}
|
}
|
||||||
if (plainValue === mockDevicePrivateKey && key === mockDeviceKey) {
|
if (plainValue === mockDevicePrivateKey && key === mockDeviceKey) {
|
||||||
return Promise.resolve(mockDeviceKeyEncryptedDevicePrivateKey);
|
return Promise.resolve(mockDeviceKeyEncryptedDevicePrivateKey);
|
||||||
@ -240,8 +240,8 @@ describe("deviceCryptoService", () => {
|
|||||||
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledTimes(1);
|
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledWith(
|
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledWith(
|
||||||
mockDeviceId,
|
mockDeviceId,
|
||||||
mockDevicePublicKeyEncryptedUserSymKey.encryptedString,
|
mockDevicePublicKeyEncryptedUserKey.encryptedString,
|
||||||
mockUserSymKeyEncryptedDevicePublicKey.encryptedString,
|
mockUserKeyEncryptedDevicePublicKey.encryptedString,
|
||||||
mockDeviceKeyEncryptedDevicePrivateKey.encryptedString
|
mockDeviceKeyEncryptedDevicePrivateKey.encryptedString
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ describe("deviceCryptoService", () => {
|
|||||||
expect(response).toEqual(mockDeviceResponse);
|
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
|
// setup the spy to return null
|
||||||
cryptoSvcGetUserKeyFromMemorySpy.mockResolvedValue(null);
|
cryptoSvcGetUserKeyFromMemorySpy.mockResolvedValue(null);
|
||||||
// check if the expected error is thrown
|
// check if the expected error is thrown
|
||||||
|
@ -41,13 +41,13 @@ export class DevicesApiServiceImplementation implements DevicesApiServiceAbstrac
|
|||||||
|
|
||||||
async updateTrustedDeviceKeys(
|
async updateTrustedDeviceKeys(
|
||||||
deviceIdentifier: string,
|
deviceIdentifier: string,
|
||||||
devicePublicKeyEncryptedUserSymKey: string,
|
devicePublicKeyEncryptedUserKey: string,
|
||||||
userSymKeyEncryptedDevicePublicKey: string,
|
userKeyEncryptedDevicePublicKey: string,
|
||||||
deviceKeyEncryptedDevicePrivateKey: string
|
deviceKeyEncryptedDevicePrivateKey: string
|
||||||
): Promise<DeviceResponse> {
|
): Promise<DeviceResponse> {
|
||||||
const request = new TrustedDeviceKeysRequest(
|
const request = new TrustedDeviceKeysRequest(
|
||||||
devicePublicKeyEncryptedUserSymKey,
|
devicePublicKeyEncryptedUserKey,
|
||||||
userSymKeyEncryptedDevicePublicKey,
|
userKeyEncryptedDevicePublicKey,
|
||||||
deviceKeyEncryptedDevicePrivateKey
|
deviceKeyEncryptedDevicePrivateKey
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
|||||||
if (await this.keyConnectorService.getUsesKeyConnector()) {
|
if (await this.keyConnectorService.getUsesKeyConnector()) {
|
||||||
const pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
|
const pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
|
||||||
|
|
||||||
let ephemeralPinSet = await this.stateService.getUserSymKeyPinEphemeral();
|
let ephemeralPinSet = await this.stateService.getUserKeyPinEphemeral();
|
||||||
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
|
ephemeralPinSet ||= await this.stateService.getDecryptedPinProtected();
|
||||||
const pinLock = (pinSet[0] && ephemeralPinSet != null) || pinSet[1];
|
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.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.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
|
||||||
|
|
||||||
await this.cryptoService.clearUserKey(false, 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
|
// we can't check the protected pin for both because old accounts only
|
||||||
// used it for MP on Restart
|
// used it for MP on Restart
|
||||||
const pinIsEnabled = !!(await this.stateService.getProtectedPin());
|
const pinIsEnabled = !!(await this.stateService.getProtectedPin());
|
||||||
const aUserSymKeyPinIsSet = !!(await this.stateService.getUserSymKeyPin());
|
const aUserKeyPinIsSet = !!(await this.stateService.getUserKeyPin());
|
||||||
const anOldUserSymKeyPinIsSet = !!(await this.stateService.getEncryptedPinProtected());
|
const anOldUserKeyPinIsSet = !!(await this.stateService.getEncryptedPinProtected());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
pinIsEnabled && !aUserSymKeyPinIsSet && !anOldUserSymKeyPinIsSet,
|
pinIsEnabled && !aUserKeyPinIsSet && !anOldUserKeyPinIsSet,
|
||||||
aUserSymKeyPinIsSet || anOldUserSymKeyPinIsSet,
|
aUserKeyPinIsSet || anOldUserKeyPinIsSet,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
|
|||||||
|
|
||||||
async clear(userId?: string): Promise<void> {
|
async clear(userId?: string): Promise<void> {
|
||||||
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
|
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.stateService.setProtectedPin(null, { userId: userId });
|
||||||
await this.cryptoService.clearOldPinKeys(userId);
|
await this.cryptoService.clearOldPinKeys(userId);
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ export class SyncService implements SyncServiceAbstraction {
|
|||||||
throw new Error("Stamp has changed");
|
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.setPrivateKey(response.privateKey);
|
||||||
await this.cryptoService.setProviderKeys(response.providers);
|
await this.cryptoService.setProviderKeys(response.providers);
|
||||||
await this.cryptoService.setOrgKeys(response.organizations, response.providerOrganizations);
|
await this.cryptoService.setOrgKeys(response.organizations, response.providerOrganizations);
|
||||||
|
Loading…
Reference in New Issue
Block a user