Skip to content
This repository has been archived by the owner on Jun 17, 2022. It is now read-only.

Commit

Permalink
Fix separate key storage for non desktop (#409)
Browse files Browse the repository at this point in the history
* Handle non-desktop, non-split key storage

* Reset vaultTimeoutService on clear.

Fixes issues where unlock was required after login

* Specify electron as desktop client

* Use ElelectronCryptoService to handle desktop-specific tasks

* Linter fixes
  • Loading branch information
MGibson1 committed Jun 15, 2021
1 parent d63ee18 commit 1f83c3c
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 50 deletions.
68 changes: 18 additions & 50 deletions common/src/services/crypto.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { sequentialize } from '../misc/sequentialize';
import { Utils } from '../misc/utils';
import { EEFLongWordList } from '../misc/wordlist';

const Keys = {
export const Keys = {
key: 'key', // Master Key
encOrgKeys: 'encOrgKeys',
encPrivateKey: 'encPrivateKey',
Expand All @@ -42,25 +42,15 @@ export class CryptoService implements CryptoServiceAbstraction {
private privateKey: ArrayBuffer;
private orgKeys: Map<string, SymmetricCryptoKey>;

constructor(private storageService: StorageService, private secureStorageService: StorageService,
private cryptoFunctionService: CryptoFunctionService, private platformUtilService: PlatformUtilsService,
private logService: LogService) {
constructor(private storageService: StorageService, protected secureStorageService: StorageService,
private cryptoFunctionService: CryptoFunctionService, protected platformUtilService: PlatformUtilsService,
protected logService: LogService) {
}

async setKey(key: SymmetricCryptoKey): Promise<any> {
this.key = key;

if (await this.shouldStoreKey('auto')) {
await this.secureStorageService.save(Keys.key, key.keyB64, { keySuffix: 'auto' });
} else {
this.clearStoredKey('auto');
}

if (await this.shouldStoreKey('biometric')) {
await this.secureStorageService.save(Keys.key, key.keyB64, { keySuffix: 'biometric' });
} else {
this.clearStoredKey('biometric');
}
await this.storeKey(key);
}

setKeyHash(keyHash: string): Promise<{}> {
Expand Down Expand Up @@ -288,9 +278,8 @@ export class CryptoService implements CryptoServiceAbstraction {
return this.key != null;
}

async hasKeyStored(keySuffix: KeySuffixOptions): Promise<boolean> {
await this.upgradeSecurelyStoredKey();
return await this.secureStorageService.has(Keys.key, { keySuffix: keySuffix });
hasKeyStored(keySuffix: KeySuffixOptions): Promise<boolean> {
return this.secureStorageService.has(Keys.key, { keySuffix: keySuffix });
}

async hasEncKey(): Promise<boolean> {
Expand Down Expand Up @@ -651,7 +640,15 @@ export class CryptoService implements CryptoServiceAbstraction {

// Helpers

private async shouldStoreKey(keySuffix: KeySuffixOptions) {
protected async storeKey(key: SymmetricCryptoKey) {
if (await this.shouldStoreKey('auto') || await this.shouldStoreKey('biometric')) {
this.secureStorageService.save(Keys.key, key.keyB64);
} else {
this.secureStorageService.remove(Keys.key);
}
}

protected async shouldStoreKey(keySuffix: KeySuffixOptions) {
let shouldStoreKey = false;
if (keySuffix === 'auto') {
const vaultTimeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
Expand All @@ -663,37 +660,8 @@ export class CryptoService implements CryptoServiceAbstraction {
return shouldStoreKey;
}

private async retrieveKeyFromStorage(keySuffix: KeySuffixOptions) {
await this.upgradeSecurelyStoredKey();

return await this.secureStorageService.get<string>(Keys.key, { keySuffix: keySuffix });
}

/**
* @deprecated 4 Jun 2021 This is temporary upgrade method to move from a single shared stored key to
* multiple, unique stored keys for each use, e.g. never logout vs. biometric authentication.
*/
private async upgradeSecurelyStoredKey() {
// attempt key upgrade, but if we fail just delete it. Keys will be stored property upon unlock anyway.
const key = await this.secureStorageService.get<string>(Keys.key);

if (key == null) {
return;
}

try {
if (await this.shouldStoreKey('auto')) {
await this.secureStorageService.save(Keys.key, key, { keySuffix: 'auto' });
}
if (await this.shouldStoreKey('biometric')) {
await this.secureStorageService.save(Keys.key, key, { keySuffix: 'biometric' });
}
} catch (e) {
this.logService.error(`Encountered error while upgrading obsolete Bitwarden secure storage item:`);
this.logService.error(e);
}

await this.secureStorageService.remove(Keys.key);
protected retrieveKeyFromStorage(keySuffix: KeySuffixOptions) {
return this.secureStorageService.get<string>(Keys.key, { keySuffix: keySuffix });
}

private async aesEncrypt(data: ArrayBuffer, key: SymmetricCryptoKey): Promise<EncryptedObject> {
Expand Down
2 changes: 2 additions & 0 deletions common/src/services/vaultTimeout.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}

clear(): Promise<any> {
this.everBeenUnlocked = false;
this.manuallyOrTimerLocked = false;
this.pinProtectedKey = null;
return this.storageService.remove(ConstantsService.protectedPin);
}
Expand Down
66 changes: 66 additions & 0 deletions electron/src/services/electronCrypto.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { KeySuffixOptions, StorageService } from 'jslib-common/abstractions/storage.service';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
import { CryptoService, Keys } from 'jslib-common/services/crypto.service';

export class ElectronCryptoService extends CryptoService {

constructor(storageService: StorageService, secureStorageService: StorageService,
cryptoFunctionService: CryptoFunctionService, platformUtilService: PlatformUtilsService,
logService: LogService) {
super(storageService, secureStorageService, cryptoFunctionService, platformUtilService, logService);
}

async hasKeyStored(keySuffix: KeySuffixOptions): Promise<boolean> {
await this.upgradeSecurelyStoredKey();
return super.hasKeyStored(keySuffix);
}

protected async storeKey(key: SymmetricCryptoKey) {
if (await this.shouldStoreKey('auto')) {
await this.secureStorageService.save(Keys.key, key.keyB64, { keySuffix: 'auto' });
} else {
this.clearStoredKey('auto');
}

if (await this.shouldStoreKey('biometric')) {
await this.secureStorageService.save(Keys.key, key.keyB64, { keySuffix: 'biometric' });
} else {
this.clearStoredKey('biometric');
}
}

protected async retrieveKeyFromStorage(keySuffix: KeySuffixOptions) {
await this.upgradeSecurelyStoredKey();
return super.retrieveKeyFromStorage(keySuffix);
}

/**
* @deprecated 4 Jun 2021 This is temporary upgrade method to move from a single shared stored key to
* multiple, unique stored keys for each use, e.g. never logout vs. biometric authentication.
*/
private async upgradeSecurelyStoredKey() {
// attempt key upgrade, but if we fail just delete it. Keys will be stored property upon unlock anyway.
const key = await this.secureStorageService.get<string>(Keys.key);

if (key == null) {
return;
}

try {
if (await this.shouldStoreKey('auto')) {
await this.secureStorageService.save(Keys.key, key, { keySuffix: 'auto' });
}
if (await this.shouldStoreKey('biometric')) {
await this.secureStorageService.save(Keys.key, key, { keySuffix: 'biometric' });
}
} catch (e) {
this.logService.error(`Encountered error while upgrading obsolete Bitwarden secure storage item:`);
this.logService.error(e);
}

await this.secureStorageService.remove(Keys.key);
}
}

0 comments on commit 1f83c3c

Please sign in to comment.