1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 21:33:27 +00:00

[PM-11477] Remove deprecated cryptoservice functions (#10854)

* Remove deprecated cryptoservice functions

* Use getUserkeyWithLegacySupport to get userkey

* Fix tests

* Fix tests

* Fix tests

* Remove unused cryptoservice instances

* Fix build

* Remove unused apiService in constructor

* Fix encryption

* Ensure passed in key is used if present

* Fix sends and folders

* Fix tests

* Remove logged key

* Fix import for account restricted keys
This commit is contained in:
Bernd Schoolmann
2024-09-24 11:28:33 +02:00
committed by GitHub
parent 6d9223fac7
commit d92b2cbea2
69 changed files with 404 additions and 197 deletions

View File

@@ -449,6 +449,7 @@ const safeProviders: SafeProvider[] = [
fileUploadService: CipherFileUploadServiceAbstraction,
configService: ConfigService,
stateProvider: StateProvider,
accountService: AccountServiceAbstraction,
) =>
new CipherService(
cryptoService,
@@ -463,6 +464,7 @@ const safeProviders: SafeProvider[] = [
fileUploadService,
configService,
stateProvider,
accountService,
),
deps: [
CryptoServiceAbstraction,
@@ -477,6 +479,7 @@ const safeProviders: SafeProvider[] = [
CipherFileUploadServiceAbstraction,
ConfigService,
StateProvider,
AccountServiceAbstraction,
],
}),
safeProvider({
@@ -484,6 +487,7 @@ const safeProviders: SafeProvider[] = [
useClass: FolderService,
deps: [
CryptoServiceAbstraction,
EncryptService,
I18nServiceAbstraction,
CipherServiceAbstraction,
StateProvider,
@@ -527,7 +531,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: CollectionServiceAbstraction,
useClass: CollectionService,
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, StateProvider],
deps: [CryptoServiceAbstraction, EncryptService, I18nServiceAbstraction, StateProvider],
}),
safeProvider({
provide: EnvironmentService,
@@ -785,6 +789,7 @@ const safeProviders: SafeProvider[] = [
I18nServiceAbstraction,
CollectionServiceAbstraction,
CryptoServiceAbstraction,
EncryptService,
PinServiceAbstraction,
AccountServiceAbstraction,
],
@@ -797,8 +802,10 @@ const safeProviders: SafeProvider[] = [
CipherServiceAbstraction,
PinServiceAbstraction,
CryptoServiceAbstraction,
EncryptService,
CryptoFunctionServiceAbstraction,
KdfConfigServiceAbstraction,
AccountServiceAbstraction,
],
}),
safeProvider({
@@ -809,6 +816,7 @@ const safeProviders: SafeProvider[] = [
ApiServiceAbstraction,
PinServiceAbstraction,
CryptoServiceAbstraction,
EncryptService,
CryptoFunctionServiceAbstraction,
CollectionServiceAbstraction,
KdfConfigServiceAbstraction,

View File

@@ -6,6 +6,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -40,6 +41,7 @@ export class AttachmentsComponent implements OnInit {
protected cipherService: CipherService,
protected i18nService: I18nService,
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService,
protected win: Window,
@@ -178,7 +180,7 @@ export class AttachmentsComponent implements OnInit {
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
this.fileDownloadService.download({
fileName: attachment.fileName,
blobData: decBuf,
@@ -249,7 +251,7 @@ export class AttachmentsComponent implements OnInit {
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);

View File

@@ -1,6 +1,9 @@
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { Validators, FormBuilder } from "@angular/forms";
import { firstValueFrom } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -29,6 +32,8 @@ export class FolderAddEditComponent implements OnInit {
constructor(
protected folderService: FolderService,
protected folderApiService: FolderApiServiceAbstraction,
protected accountService: AccountService,
protected cryptoService: CryptoService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected logService: LogService,
@@ -52,7 +57,9 @@ export class FolderAddEditComponent implements OnInit {
}
try {
const folder = await this.folderService.encrypt(this.folder);
const activeAccountId = await firstValueFrom(this.accountService.activeAccount$);
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeAccountId.id);
const folder = await this.folderService.encrypt(this.folder, userKey);
this.formPromise = this.folderApiService.save(folder);
await this.formPromise;
this.platformUtilsService.showToast(

View File

@@ -21,6 +21,7 @@ import { EventType } from "@bitwarden/common/enums";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -87,6 +88,7 @@ export class ViewComponent implements OnDestroy, OnInit {
protected tokenService: TokenService,
protected i18nService: I18nService,
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService,
protected win: Window,
@@ -442,7 +444,7 @@ export class ViewComponent implements OnDestroy, OnInit {
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
this.fileDownloadService.download({
fileName: attachment.fileName,
blobData: decBuf,

View File

@@ -12,6 +12,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -37,6 +38,7 @@ describe("AuthRequestLoginStrategy", () => {
let cache: AuthRequestLoginStrategyData;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
@@ -101,6 +103,7 @@ describe("AuthRequestLoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,

View File

@@ -22,6 +22,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -104,6 +105,7 @@ describe("LoginStrategy", () => {
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
@@ -128,6 +130,7 @@ describe("LoginStrategy", () => {
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
@@ -156,6 +159,7 @@ describe("LoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,
@@ -467,6 +471,7 @@ describe("LoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,

View File

@@ -26,6 +26,7 @@ import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -66,6 +67,7 @@ export abstract class LoginStrategy {
protected accountService: AccountService,
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
protected apiService: ApiService,
protected tokenService: TokenService,
protected appIdService: AppIdService,

View File

@@ -16,6 +16,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -63,6 +64,7 @@ describe("PasswordLoginStrategy", () => {
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
@@ -88,6 +90,7 @@ describe("PasswordLoginStrategy", () => {
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
@@ -127,6 +130,7 @@ describe("PasswordLoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,

View File

@@ -17,6 +17,7 @@ import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@@ -44,6 +45,7 @@ describe("SsoLoginStrategy", () => {
let masterPasswordService: FakeMasterPasswordService;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
@@ -78,6 +80,7 @@ describe("SsoLoginStrategy", () => {
masterPasswordService = new FakeMasterPasswordService();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
@@ -125,6 +128,7 @@ describe("SsoLoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,

View File

@@ -11,6 +11,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import {
Environment,
EnvironmentService,
@@ -39,6 +40,7 @@ describe("UserApiLoginStrategy", () => {
let masterPasswordService: FakeMasterPasswordService;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
@@ -99,6 +101,7 @@ describe("UserApiLoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,

View File

@@ -14,6 +14,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -37,6 +38,7 @@ describe("WebAuthnLoginStrategy", () => {
let masterPasswordService: FakeMasterPasswordService;
let cryptoService!: MockProxy<CryptoService>;
let encryptService!: MockProxy<EncryptService>;
let apiService!: MockProxy<ApiService>;
let tokenService!: MockProxy<TokenService>;
let appIdService!: MockProxy<AppIdService>;
@@ -79,6 +81,7 @@ describe("WebAuthnLoginStrategy", () => {
masterPasswordService = new FakeMasterPasswordService();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
@@ -103,6 +106,7 @@ describe("WebAuthnLoginStrategy", () => {
accountService,
masterPasswordService,
cryptoService,
encryptService,
apiService,
tokenService,
appIdService,
@@ -221,7 +225,7 @@ describe("WebAuthnLoginStrategy", () => {
const mockUserKeyArray: Uint8Array = randomBytes(32);
const mockUserKey = new SymmetricCryptoKey(mockUserKeyArray) as UserKey;
cryptoService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
encryptService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
cryptoService.rsaDecrypt.mockResolvedValue(mockUserKeyArray);
// Act
@@ -235,8 +239,8 @@ describe("WebAuthnLoginStrategy", () => {
userId,
);
expect(cryptoService.decryptToBytes).toHaveBeenCalledTimes(1);
expect(cryptoService.decryptToBytes).toHaveBeenCalledWith(
expect(encryptService.decryptToBytes).toHaveBeenCalledTimes(1);
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedPrivateKey,
webAuthnCredentials.prfKey,
);
@@ -268,7 +272,7 @@ describe("WebAuthnLoginStrategy", () => {
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
// Assert
expect(cryptoService.decryptToBytes).not.toHaveBeenCalled();
expect(encryptService.decryptToBytes).not.toHaveBeenCalled();
expect(cryptoService.rsaDecrypt).not.toHaveBeenCalled();
expect(cryptoService.setUserKey).not.toHaveBeenCalled();
});
@@ -303,7 +307,7 @@ describe("WebAuthnLoginStrategy", () => {
apiService.postIdentityToken.mockResolvedValue(idTokenResponse);
cryptoService.decryptToBytes.mockResolvedValue(null);
encryptService.decryptToBytes.mockResolvedValue(null);
// Act
await webAuthnLoginStrategy.logIn(webAuthnCredentials);

View File

@@ -80,7 +80,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
}
// decrypt prf encrypted private key
const privateKey = await this.cryptoService.decryptToBytes(
const privateKey = await this.encryptService.decryptToBytes(
webAuthnPrfOption.encryptedPrivateKey,
credentials.prfKey,
);

View File

@@ -317,6 +317,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
this.accountService,
this.masterPasswordService,
this.cryptoService,
this.encryptService,
this.apiService,
this.tokenService,
this.appIdService,

View File

@@ -15,7 +15,6 @@ import {
UserPublicKey,
} from "../../types/key";
import { KeySuffixOptions, HashPurpose } from "../enums";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
@@ -373,37 +372,6 @@ export abstract class CryptoService {
* @param userId The desired user
*/
abstract clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: string): Promise<void>;
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.encrypt
*/
abstract encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString>;
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.encryptToBytes
*/
abstract encryptToBytes(
plainValue: Uint8Array,
key?: SymmetricCryptoKey,
): Promise<EncArrayBuffer>;
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToBytes
*/
abstract decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array>;
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToUtf8
*/
abstract decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string>;
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToBytes
*/
abstract decryptFromBytes(
encBuffer: EncArrayBuffer,
key: SymmetricCryptoKey,
): Promise<Uint8Array>;
/**
* Retrieves all the keys needed for decrypting Ciphers

View File

@@ -48,7 +48,6 @@ import { StateService } from "../abstractions/state.service";
import { KeySuffixOptions, HashPurpose, EncryptionType } from "../enums";
import { convertValues } from "../misc/convert-values";
import { EFFLongWordList } from "../misc/wordlist";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString, EncryptedString } from "../models/domain/enc-string";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
import { ActiveUserState, StateProvider } from "../state";
@@ -859,58 +858,6 @@ export class CryptoService implements CryptoServiceAbstraction {
}
}
// --DEPRECATED METHODS--
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.encrypt
*/
async encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString> {
key ||= await this.getUserKeyWithLegacySupport();
return await this.encryptService.encrypt(plainValue, key);
}
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.encryptToBytes
*/
async encryptToBytes(plainValue: Uint8Array, key?: SymmetricCryptoKey): Promise<EncArrayBuffer> {
key ||= await this.getUserKeyWithLegacySupport();
return this.encryptService.encryptToBytes(plainValue, key);
}
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToBytes
*/
async decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array> {
key ||= await this.getUserKeyWithLegacySupport();
return this.encryptService.decryptToBytes(encString, key);
}
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToUtf8
*/
async decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string> {
key ||= await this.getUserKeyWithLegacySupport();
return await this.encryptService.decryptToUtf8(encString, key);
}
/**
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
* and then call encryptService.decryptToBytes
*/
async decryptFromBytes(encBuffer: EncArrayBuffer, key: SymmetricCryptoKey): Promise<Uint8Array> {
if (encBuffer == null) {
throw new Error("No buffer provided for decryption.");
}
key ||= await this.getUserKeyWithLegacySupport();
return this.encryptService.decryptToBytes(encBuffer, key);
}
userKey$(userId: UserId): Observable<UserKey> {
return this.stateProvider.getUser(userId, USER_KEY).state$;
}

View File

@@ -1,5 +1,8 @@
import { mock } from "jest-mock-extended";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { UserKey } from "@bitwarden/common/types/key";
import { makeStaticByteArray, mockEnc } from "../../../../../spec";
import { CryptoService } from "../../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../../platform/abstractions/encrypt.service";
@@ -89,6 +92,7 @@ describe("Send", () => {
it("Decrypt", async () => {
const text = mock<SendText>();
text.decrypt.mockResolvedValue("textView" as any);
const userKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const send = new Send();
send.id = "id";
@@ -106,13 +110,13 @@ describe("Send", () => {
send.disabled = false;
send.hideEmail = true;
const encryptService = mock<EncryptService>();
const cryptoService = mock<CryptoService>();
cryptoService.decryptToBytes
.calledWith(send.key, null)
encryptService.decryptToBytes
.calledWith(send.key, userKey)
.mockResolvedValue(makeStaticByteArray(32));
cryptoService.makeSendKey.mockResolvedValue("cryptoKey" as any);
const encryptService = mock<EncryptService>();
cryptoService.getUserKey.mockResolvedValue(userKey);
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);

View File

@@ -73,9 +73,11 @@ export class Send extends Domain {
const model = new SendView(this);
const cryptoService = Utils.getContainerService().getCryptoService();
const encryptService = Utils.getContainerService().getEncryptService();
try {
model.key = await cryptoService.decryptToBytes(this.key, null);
const sendKeyEncryptionKey = await cryptoService.getUserKey();
model.key = await encryptService.decryptToBytes(this.key, sendKeyEncryptionKey);
model.cryptoKey = await cryptoService.makeSendKey(model.key);
} catch (e) {
// TODO: error?

View File

@@ -15,7 +15,7 @@ export abstract class FolderService implements UserKeyRotationDataProvider<Folde
folderViews$: Observable<FolderView[]>;
clearCache: () => Promise<void>;
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
encrypt: (model: FolderView, key: SymmetricCryptoKey) => Promise<Folder>;
get: (id: string) => Promise<Folder>;
getDecrypted$: (id: string) => Observable<FolderView | undefined>;
getAllFromState: () => Promise<Folder[]>;

View File

@@ -145,6 +145,7 @@ describe("Cipher Service", () => {
cipherFileUploadService,
configService,
stateProvider,
accountService,
);
cipherObj = new Cipher(cipherData);
@@ -273,7 +274,7 @@ describe("Cipher Service", () => {
cryptoService.makeCipherKey.mockReturnValue(
Promise.resolve(new SymmetricCryptoKey(makeStaticByteArray(64)) as CipherKey),
);
cryptoService.encrypt.mockImplementation(encryptText);
encryptService.encrypt.mockImplementation(encryptText);
jest.spyOn(cipherService as any, "getAutofillOnPageLoadDefault").mockResolvedValue(true);
});
@@ -285,6 +286,10 @@ describe("Cipher Service", () => {
{ uri: "uri", match: UriMatchStrategy.RegularExpression } as LoginUriView,
];
cryptoService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
const domain = await cipherService.encrypt(cipherView, userId);
expect(domain.login.uris).toEqual([
@@ -301,6 +306,9 @@ describe("Cipher Service", () => {
it("is null when feature flag is false", async () => {
configService.getFeatureFlag.mockResolvedValue(false);
cryptoService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
const cipher = await cipherService.encrypt(cipherView, userId);
expect(cipher.key).toBeNull();
@@ -322,6 +330,9 @@ describe("Cipher Service", () => {
it("is not called when feature flag is false", async () => {
configService.getFeatureFlag.mockResolvedValue(false);
cryptoService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
await cipherService.encrypt(cipherView, userId);
@@ -330,6 +341,9 @@ describe("Cipher Service", () => {
it("is called when feature flag is true", async () => {
configService.getFeatureFlag.mockResolvedValue(true);
cryptoService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
await cipherService.encrypt(cipherView, userId);

View File

@@ -1,6 +1,7 @@
import { firstValueFrom, map, Observable, skipWhile, switchMap } from "rxjs";
import { SemVer } from "semver";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
@@ -108,6 +109,7 @@ export class CipherService implements CipherServiceAbstraction {
private cipherFileUploadService: CipherFileUploadService,
private configService: ConfigService,
private stateProvider: StateProvider,
private accountService: AccountService,
) {
this.localDataState = this.stateProvider.getActive(LOCAL_DATA_KEY);
this.encryptedCiphersState = this.stateProvider.getActive(ENCRYPTED_CIPHERS);
@@ -165,7 +167,7 @@ export class CipherService implements CipherServiceAbstraction {
async encrypt(
model: CipherView,
userId: UserId,
keyForEncryption?: SymmetricCryptoKey,
keyForCipherEncryption?: SymmetricCryptoKey,
keyForCipherKeyDecryption?: SymmetricCryptoKey,
originalCipher: Cipher = null,
): Promise<Cipher> {
@@ -195,26 +197,21 @@ export class CipherService implements CipherServiceAbstraction {
const userOrOrgKey = await this.getKeyForCipherKeyDecryption(cipher, userId);
// The keyForEncryption is only used for encrypting the cipher key, not the cipher itself, since cipher key encryption is enabled.
// If the caller has provided a key for cipher key encryption, use it. Otherwise, use the user or org key.
keyForEncryption ||= userOrOrgKey;
keyForCipherEncryption ||= userOrOrgKey;
// If the caller has provided a key for cipher key decryption, use it. Otherwise, use the user or org key.
keyForCipherKeyDecryption ||= userOrOrgKey;
return this.encryptCipherWithCipherKey(
model,
cipher,
keyForEncryption,
keyForCipherEncryption,
keyForCipherKeyDecryption,
);
} else {
if (keyForEncryption == null && cipher.organizationId != null) {
keyForEncryption = await this.cryptoService.getOrgKey(cipher.organizationId);
if (keyForEncryption == null) {
throw new Error("Cannot encrypt cipher for organization. No key.");
}
}
keyForCipherEncryption ||= await this.getKeyForCipherKeyDecryption(cipher, userId);
// We want to ensure that the cipher key is null if cipher key encryption is disabled
// so that decryption uses the proper key.
cipher.key = null;
return this.encryptCipher(model, cipher, keyForEncryption);
return this.encryptCipher(model, cipher, keyForCipherEncryption);
}
}
@@ -243,7 +240,7 @@ export class CipherService implements CipherServiceAbstraction {
key,
).then(async () => {
if (model.key != null) {
attachment.key = await this.cryptoService.encrypt(model.key.key, key);
attachment.key = await this.encryptService.encrypt(model.key.key, key);
}
encAttachments.push(attachment);
});
@@ -1348,7 +1345,9 @@ export class CipherService implements CipherServiceAbstraction {
}
const encBuf = await EncArrayBuffer.fromResponse(attachmentResponse);
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, null);
const activeUserId = await firstValueFrom(this.accountService.activeAccount$);
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId.id);
const decBuf = await this.encryptService.decryptToBytes(encBuf, userKey);
let encKey: UserKey | OrgKey;
encKey = await this.cryptoService.getOrgKey(organizationId);
@@ -1412,7 +1411,7 @@ export class CipherService implements CipherServiceAbstraction {
.then(() => {
const modelProp = (model as any)[map[theProp] || theProp];
if (modelProp && modelProp !== "") {
return self.cryptoService.encrypt(modelProp, key);
return self.encryptService.encrypt(modelProp, key);
}
return null;
})
@@ -1458,7 +1457,7 @@ export class CipherService implements CipherServiceAbstraction {
key,
);
const uriHash = await this.encryptService.hash(model.login.uris[i].uri, "sha256");
loginUri.uriChecksum = await this.cryptoService.encrypt(uriHash, key);
loginUri.uriChecksum = await this.encryptService.encrypt(uriHash, key);
cipher.login.uris.push(loginUri);
}
}
@@ -1485,8 +1484,8 @@ export class CipherService implements CipherServiceAbstraction {
},
key,
);
domainKey.counter = await this.cryptoService.encrypt(String(viewKey.counter), key);
domainKey.discoverable = await this.cryptoService.encrypt(
domainKey.counter = await this.encryptService.encrypt(String(viewKey.counter), key);
domainKey.discoverable = await this.encryptService.encrypt(
String(viewKey.discoverable),
key,
);
@@ -1605,11 +1604,23 @@ export class CipherService implements CipherServiceAbstraction {
this.sortedCiphersCache.clear();
}
/**
* Encrypts a cipher object.
* @param model The cipher view model.
* @param cipher The cipher object.
* @param key The encryption key to encrypt with. This can be the org key, user key or cipher key, but must never be null
*/
private async encryptCipher(
model: CipherView,
cipher: Cipher,
key: SymmetricCryptoKey,
): Promise<Cipher> {
if (key == null) {
throw new Error(
"Key to encrypt cipher must not be null. Use the org key, user key or cipher key.",
);
}
await Promise.all([
this.encryptObjProperty(
model,

View File

@@ -1,6 +1,8 @@
import { firstValueFrom, map, Observable } from "rxjs";
import { Jsonify } from "type-fest";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { Utils } from "../../platform/misc/utils";
@@ -61,6 +63,7 @@ export class CollectionService implements CollectionServiceAbstraction {
constructor(
private cryptoService: CryptoService,
private encryptService: EncryptService,
private i18nService: I18nService,
protected stateProvider: StateProvider,
) {
@@ -101,7 +104,7 @@ export class CollectionService implements CollectionServiceAbstraction {
collection.organizationId = model.organizationId;
collection.readOnly = model.readOnly;
collection.externalId = model.externalId;
collection.name = await this.cryptoService.encrypt(model.name, key);
collection.name = await this.encryptService.encrypt(model.name, key);
return collection;
}

View File

@@ -49,7 +49,13 @@ describe("Folder Service", () => {
);
encryptService.decryptToUtf8.mockResolvedValue("DEC");
folderService = new FolderService(cryptoService, i18nService, cipherService, stateProvider);
folderService = new FolderService(
cryptoService,
encryptService,
i18nService,
cipherService,
stateProvider,
);
folderState = stateProvider.activeUser.getFake(FOLDER_ENCRYPTED_FOLDERS);
@@ -62,9 +68,9 @@ describe("Folder Service", () => {
model.id = "2";
model.name = "Test Folder";
cryptoService.encrypt.mockResolvedValue(new EncString("ENC"));
encryptService.encrypt.mockResolvedValue(new EncString("ENC"));
const result = await folderService.encrypt(model);
const result = await folderService.encrypt(model, null);
expect(result).toEqual({
id: "2",
@@ -185,7 +191,7 @@ describe("Folder Service", () => {
beforeEach(() => {
encryptedKey = new EncString("Re-encrypted Folder");
cryptoService.encrypt.mockResolvedValue(encryptedKey);
encryptService.encrypt.mockResolvedValue(encryptedKey);
});
it("returns re-encrypted user folders", async () => {

View File

@@ -1,5 +1,7 @@
import { Observable, firstValueFrom, map, shareReplay } from "rxjs";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { Utils } from "../../../platform/misc/utils";
@@ -25,6 +27,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
constructor(
private cryptoService: CryptoService,
private encryptService: EncryptService,
private i18nService: I18nService,
private cipherService: CipherService,
private stateProvider: StateProvider,
@@ -48,10 +51,10 @@ export class FolderService implements InternalFolderServiceAbstraction {
}
// TODO: This should be moved to EncryptService or something
async encrypt(model: FolderView, key?: SymmetricCryptoKey): Promise<Folder> {
async encrypt(model: FolderView, key: SymmetricCryptoKey): Promise<Folder> {
const folder = new Folder();
folder.id = model.id;
folder.name = await this.cryptoService.encrypt(model.name, key);
folder.name = await this.encryptService.encrypt(model.name, key);
return folder;
}

View File

@@ -3,6 +3,7 @@ import { mock, MockProxy } from "jest-mock-extended";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { KdfType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@@ -19,6 +20,7 @@ import { emptyUnencryptedExport } from "./test-data/bitwarden-json/unencrypted.j
describe("BitwardenPasswordProtectedImporter", () => {
let importer: BitwardenPasswordProtectedImporter;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let i18nService: MockProxy<I18nService>;
let cipherService: MockProxy<CipherService>;
let pinService: MockProxy<PinServiceAbstraction>;
@@ -30,6 +32,7 @@ describe("BitwardenPasswordProtectedImporter", () => {
beforeEach(() => {
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
i18nService = mock<I18nService>();
cipherService = mock<CipherService>();
pinService = mock<PinServiceAbstraction>();
@@ -37,6 +40,7 @@ describe("BitwardenPasswordProtectedImporter", () => {
importer = new BitwardenPasswordProtectedImporter(
cryptoService,
encryptService,
i18nService,
cipherService,
pinService,
@@ -91,7 +95,7 @@ describe("BitwardenPasswordProtectedImporter", () => {
});
it("succeeds with default jdoc", async () => {
cryptoService.decryptToUtf8.mockReturnValue(Promise.resolve(emptyUnencryptedExport));
encryptService.decryptToUtf8.mockReturnValue(Promise.resolve(emptyUnencryptedExport));
expect((await importer.parse(JSON.stringify(jDoc))).success).toEqual(true);
});

View File

@@ -30,6 +30,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ClientType } from "@bitwarden/common/enums";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -89,6 +90,7 @@ const safeProviders: SafeProvider[] = [
I18nService,
CollectionService,
CryptoService,
EncryptService,
PinServiceAbstraction,
AccountService,
],

View File

@@ -8,8 +8,10 @@ import {
FolderWithIdExport,
} from "@bitwarden/common/models/export";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
@@ -31,6 +33,7 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
protected constructor(
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
protected i18nService: I18nService,
protected cipherService: CipherService,
protected pinService: PinServiceAbstraction,
@@ -60,11 +63,16 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
results: BitwardenEncryptedIndividualJsonExport | BitwardenEncryptedOrgJsonExport,
) {
if (results.encKeyValidation_DO_NOT_EDIT != null) {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
let keyForDecryption: SymmetricCryptoKey = await this.cryptoService.getOrgKey(
this.organizationId,
);
if (keyForDecryption == null) {
keyForDecryption = await this.cryptoService.getUserKeyWithLegacySupport();
}
const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT);
const encKeyValidationDecrypt = await this.cryptoService.decryptToUtf8(
const encKeyValidationDecrypt = await this.encryptService.decryptToUtf8(
encKeyValidation,
orgKey,
keyForDecryption,
);
if (encKeyValidationDecrypt === null) {
this.result.success = false;

View File

@@ -6,6 +6,7 @@ import {
PBKDF2KdfConfig,
} from "@bitwarden/common/auth/models/domain/kdf-config";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { KdfType } from "@bitwarden/common/platform/enums";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
@@ -23,13 +24,14 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
constructor(
cryptoService: CryptoService,
encryptService: EncryptService,
i18nService: I18nService,
cipherService: CipherService,
pinService: PinServiceAbstraction,
accountService: AccountService,
private promptForPassword_callback: () => Promise<string>,
) {
super(cryptoService, i18nService, cipherService, pinService, accountService);
super(cryptoService, encryptService, i18nService, cipherService, pinService, accountService);
}
async parse(data: string): Promise<ImportResult> {
@@ -65,7 +67,7 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
}
const encData = new EncString(parsedData.data);
const clearTextData = await this.cryptoService.decryptToUtf8(encData, this.key);
const clearTextData = await this.encryptService.decryptToUtf8(encData, this.key);
return await super.parse(clearTextData);
}
@@ -86,7 +88,7 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
const encKeyValidation = new EncString(jdoc.encKeyValidation_DO_NOT_EDIT);
const encKeyValidationDecrypt = await this.cryptoService.decryptToUtf8(
const encKeyValidationDecrypt = await this.encryptService.decryptToUtf8(
encKeyValidation,
this.key,
);

View File

@@ -3,6 +3,7 @@ import { mock, MockProxy } from "jest-mock-extended";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
@@ -27,6 +28,7 @@ describe("ImportService", () => {
let i18nService: MockProxy<I18nService>;
let collectionService: MockProxy<CollectionService>;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let pinService: MockProxy<PinServiceAbstraction>;
let accountService: MockProxy<AccountService>;
@@ -37,6 +39,7 @@ describe("ImportService", () => {
i18nService = mock<I18nService>();
collectionService = mock<CollectionService>();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
pinService = mock<PinServiceAbstraction>();
importService = new ImportService(
@@ -46,6 +49,7 @@ describe("ImportService", () => {
i18nService,
collectionService,
cryptoService,
encryptService,
pinService,
accountService,
);

View File

@@ -7,6 +7,7 @@ import { ImportOrganizationCiphersRequest } from "@bitwarden/common/models/reque
import { KvpRequest } from "@bitwarden/common/models/request/kvp.request";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
@@ -104,6 +105,7 @@ export class ImportService implements ImportServiceAbstraction {
private i18nService: I18nService,
private collectionService: CollectionService,
private cryptoService: CryptoService,
private encryptService: EncryptService,
private pinService: PinServiceAbstraction,
private accountService: AccountService,
) {}
@@ -207,6 +209,7 @@ export class ImportService implements ImportServiceAbstraction {
case "bitwardenpasswordprotected":
return new BitwardenPasswordProtectedImporter(
this.cryptoService,
this.encryptService,
this.i18nService,
this.cipherService,
this.pinService,
@@ -344,9 +347,10 @@ export class ImportService implements ImportServiceAbstraction {
const c = await this.cipherService.encrypt(importResult.ciphers[i], activeUserId);
request.ciphers.push(new CipherRequest(c));
}
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId);
if (importResult.folders != null) {
for (let i = 0; i < importResult.folders.length; i++) {
const f = await this.folderService.encrypt(importResult.folders[i]);
const f = await this.folderService.encrypt(importResult.folders[i], userKey);
request.folders.push(new FolderWithIdRequest(f));
}
}

View File

@@ -2,7 +2,7 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { KdfType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherType } from "@bitwarden/common/vault/enums";
@@ -12,7 +12,7 @@ import { BitwardenCsvExportType, BitwardenPasswordProtectedFileFormat } from "..
export class BaseVaultExportService {
constructor(
protected pinService: PinServiceAbstraction,
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
private cryptoFunctionService: CryptoFunctionService,
private kdfConfigService: KdfConfigService,
) {}
@@ -23,8 +23,8 @@ export class BaseVaultExportService {
const salt = Utils.fromBufferToB64(await this.cryptoFunctionService.randomBytes(16));
const key = await this.pinService.makePinKey(password, salt, kdfConfig);
const encKeyValidation = await this.cryptoService.encrypt(Utils.newGuid(), key);
const encText = await this.cryptoService.encrypt(clearText, key);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), key);
const encText = await this.encryptService.encrypt(clearText, key);
const jsonDoc: BitwardenPasswordProtectedFileFormat = {
encrypted: true,

View File

@@ -1,6 +1,8 @@
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import {
DEFAULT_KDF_CONFIG,
@@ -9,9 +11,11 @@ import {
import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { KdfType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherType } from "@bitwarden/common/vault/enums";
@@ -149,7 +153,9 @@ describe("VaultExportService", () => {
let pinService: MockProxy<PinServiceAbstraction>;
let folderService: MockProxy<FolderService>;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let kdfConfigService: MockProxy<KdfConfigService>;
let accountService: MockProxy<AccountService>;
beforeEach(() => {
cryptoFunctionService = mock<CryptoFunctionService>();
@@ -157,20 +163,35 @@ describe("VaultExportService", () => {
pinService = mock<PinServiceAbstraction>();
folderService = mock<FolderService>();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
kdfConfigService = mock<KdfConfigService>();
accountService = mock<AccountService>();
cryptoService.userKey$.mockReturnValue(new BehaviorSubject("mockOriginalUserKey" as any));
const userId = "" as UserId;
const accountInfo: AccountInfo = {
email: "",
emailVerified: true,
name: undefined,
};
const activeAccount = { id: userId, ...accountInfo };
accountService.activeAccount$ = new BehaviorSubject(activeAccount);
folderService.getAllDecryptedFromState.mockResolvedValue(UserFolderViews);
folderService.getAllFromState.mockResolvedValue(UserFolders);
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
cryptoService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
exportService = new IndividualVaultExportService(
folderService,
cipherService,
pinService,
cryptoService,
encryptService,
cryptoFunctionService,
kdfConfigService,
accountService,
);
});
@@ -250,7 +271,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
cryptoService.encrypt.mockResolvedValue(mac);
encryptService.encrypt.mockResolvedValue(mac);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
@@ -258,7 +279,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
cryptoService.encrypt.mockResolvedValue(data);
encryptService.encrypt.mockResolvedValue(data);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);

View File

@@ -1,10 +1,13 @@
import * as papa from "papaparse";
import { firstValueFrom, map } from "rxjs";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import { CipherWithIdExport, FolderWithIdExport } from "@bitwarden/common/models/export";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@@ -32,11 +35,13 @@ export class IndividualVaultExportService
private folderService: FolderService,
private cipherService: CipherService,
pinService: PinServiceAbstraction,
cryptoService: CryptoService,
private cryptoService: CryptoService,
encryptService: EncryptService,
cryptoFunctionService: CryptoFunctionService,
kdfConfigService: KdfConfigService,
private accountService: AccountService,
) {
super(pinService, cryptoService, cryptoFunctionService, kdfConfigService);
super(pinService, encryptService, cryptoFunctionService, kdfConfigService);
}
async getExport(format: ExportFormat = "csv"): Promise<string> {
@@ -96,7 +101,11 @@ export class IndividualVaultExportService
await Promise.all(promises);
const encKeyValidation = await this.cryptoService.encrypt(Utils.newGuid());
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), userKey);
const jsonDoc: BitwardenEncryptedIndividualJsonExport = {
encrypted: true,

View File

@@ -8,6 +8,7 @@ import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config
import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
@@ -39,13 +40,14 @@ export class OrganizationVaultExportService
private cipherService: CipherService,
private apiService: ApiService,
pinService: PinServiceAbstraction,
cryptoService: CryptoService,
private cryptoService: CryptoService,
encryptService: EncryptService,
cryptoFunctionService: CryptoFunctionService,
private collectionService: CollectionService,
kdfConfigService: KdfConfigService,
private accountService: AccountService,
) {
super(pinService, cryptoService, cryptoFunctionService, kdfConfigService);
super(pinService, encryptService, cryptoFunctionService, kdfConfigService);
}
async getPasswordProtectedExport(
@@ -242,7 +244,7 @@ export class OrganizationVaultExportService
ciphers: Cipher[],
): Promise<string> {
const orgKey = await this.cryptoService.getOrgKey(organizationId);
const encKeyValidation = await this.cryptoService.encrypt(Utils.newGuid(), orgKey);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), orgKey);
const jsonDoc: BitwardenEncryptedOrgJsonExport = {
encrypted: true,

View File

@@ -1,6 +1,8 @@
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import {
DEFAULT_KDF_CONFIG,
@@ -9,9 +11,11 @@ import {
import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { KdfType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherType } from "@bitwarden/common/vault/enums";
@@ -149,6 +153,8 @@ describe("VaultExportService", () => {
let pinService: MockProxy<PinServiceAbstraction>;
let folderService: MockProxy<FolderService>;
let cryptoService: MockProxy<CryptoService>;
let encryptService: MockProxy<EncryptService>;
let accountService: MockProxy<AccountService>;
let kdfConfigService: MockProxy<KdfConfigService>;
beforeEach(() => {
@@ -157,20 +163,34 @@ describe("VaultExportService", () => {
pinService = mock<PinServiceAbstraction>();
folderService = mock<FolderService>();
cryptoService = mock<CryptoService>();
encryptService = mock<EncryptService>();
accountService = mock<AccountService>();
kdfConfigService = mock<KdfConfigService>();
folderService.getAllDecryptedFromState.mockResolvedValue(UserFolderViews);
folderService.getAllFromState.mockResolvedValue(UserFolders);
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
cryptoService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
cryptoService.userKey$.mockReturnValue(new BehaviorSubject("mockOriginalUserKey" as any));
const userId = "" as UserId;
const accountInfo: AccountInfo = {
email: "",
emailVerified: true,
name: undefined,
};
const activeAccount = { id: userId, ...accountInfo };
accountService.activeAccount$ = new BehaviorSubject(activeAccount);
exportService = new IndividualVaultExportService(
folderService,
cipherService,
pinService,
cryptoService,
encryptService,
cryptoFunctionService,
kdfConfigService,
accountService,
);
});
@@ -250,7 +270,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
cryptoService.encrypt.mockResolvedValue(mac);
encryptService.encrypt.mockResolvedValue(mac);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
@@ -258,7 +278,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
cryptoService.encrypt.mockResolvedValue(data);
encryptService.encrypt.mockResolvedValue(data);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);