diff --git a/libs/common/src/platform/abstractions/crypto.service.ts b/libs/common/src/platform/abstractions/crypto.service.ts index 1284ebbd59..af468eea93 100644 --- a/libs/common/src/platform/abstractions/crypto.service.ts +++ b/libs/common/src/platform/abstractions/crypto.service.ts @@ -7,6 +7,7 @@ import { EncArrayBuffer } from "../models/domain/enc-array-buffer"; import { EncString } from "../models/domain/enc-string"; import { MasterKey, + OrgKey, PinKey, SymmetricCryptoKey, UserSymKey, @@ -188,11 +189,16 @@ export abstract class CryptoService { * @param orgId The desired organization * @returns The organization's symmetric key */ - getOrgKey: (orgId: string) => Promise; + getOrgKey: (orgId: string) => Promise; /** * @returns A map of the organization Ids to their symmetric keys */ getOrgKeys: () => Promise>; + /** + * Uses the org key to derive a new symmetric key for encrypting data + * @param orgKey The organization's symmetric key + */ + makeOrgDataEncKey: (orgKey: OrgKey) => Promise<[SymmetricCryptoKey, EncString]>; /** * Clears the user's stored organization keys * @param memoryOnly Clear only the in-memory keys diff --git a/libs/common/src/platform/models/domain/symmetric-crypto-key.ts b/libs/common/src/platform/models/domain/symmetric-crypto-key.ts index 9ef8324da7..98552ee38e 100644 --- a/libs/common/src/platform/models/domain/symmetric-crypto-key.ts +++ b/libs/common/src/platform/models/domain/symmetric-crypto-key.ts @@ -81,3 +81,4 @@ export type DeviceKey = Opaque; export type UserSymKey = Opaque; export type MasterKey = Opaque; export type PinKey = Opaque; +export type OrgKey = Opaque; diff --git a/libs/common/src/platform/services/crypto.service.ts b/libs/common/src/platform/services/crypto.service.ts index 3c28e48681..e7d0a24dd8 100644 --- a/libs/common/src/platform/services/crypto.service.ts +++ b/libs/common/src/platform/services/crypto.service.ts @@ -28,6 +28,7 @@ import { EncArrayBuffer } from "../models/domain/enc-array-buffer"; import { EncString } from "../models/domain/enc-string"; import { MasterKey, + OrgKey, PinKey, SymmetricCryptoKey, UserSymKey, @@ -114,7 +115,7 @@ export class CryptoService implements CryptoServiceAbstraction { } const newUserSymKey = await this.cryptoFunctionService.randomBytes(64); - return this.buildProtectedUserSymKey(masterKey, newUserSymKey); + return this.buildProtectedSymmetricKey(masterKey, newUserSymKey); } async clearUserKey(clearStoredKeys = true, userId?: string): Promise { @@ -155,7 +156,7 @@ export class CryptoService implements CryptoServiceAbstraction { userSymKey?: UserSymKey ): Promise<[UserSymKey, EncString]> { userSymKey ||= await this.getUserKeyFromMemory(); - return this.buildProtectedUserSymKey(masterKey, userSymKey.key); + return this.buildProtectedSymmetricKey(masterKey, userSymKey.key); } async decryptUserSymKeyWithMasterKey( @@ -271,7 +272,7 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.stateService.setEncryptedOrganizationKeys(encOrgKeyData); } - async getOrgKey(orgId: string): Promise { + async getOrgKey(orgId: string): Promise { if (orgId == null) { return null; } @@ -285,11 +286,11 @@ export class CryptoService implements CryptoServiceAbstraction { } @sequentialize(() => "getOrgKeys") - async getOrgKeys(): Promise> { - const result: Map = new Map(); + async getOrgKeys(): Promise> { + const result: Map = new Map(); const decryptedOrganizationKeys = await this.stateService.getDecryptedOrganizationKeys(); if (decryptedOrganizationKeys != null && decryptedOrganizationKeys.size > 0) { - return decryptedOrganizationKeys; + return decryptedOrganizationKeys as Map; } const encOrgKeyData = await this.stateService.getEncryptedOrganizationKeys(); @@ -305,7 +306,7 @@ export class CryptoService implements CryptoServiceAbstraction { } const encOrgKey = BaseEncryptedOrganizationKey.fromData(encOrgKeyData[orgId]); - const decOrgKey = await encOrgKey.decrypt(this); + const decOrgKey = (await encOrgKey.decrypt(this)) as OrgKey; result.set(orgId, decOrgKey); setKey = true; @@ -318,6 +319,15 @@ export class CryptoService implements CryptoServiceAbstraction { return result; } + async makeOrgDataEncKey(orgKey: OrgKey): Promise<[SymmetricCryptoKey, EncString]> { + if (orgKey == null) { + throw new Error("No Org Key provided"); + } + + const newSymKey = await this.cryptoFunctionService.randomBytes(64); + return this.buildProtectedSymmetricKey(orgKey, newSymKey); + } + async clearOrgKeys(memoryOnly?: boolean, userId?: string): Promise { await this.stateService.setDecryptedOrganizationKeys(null, { userId: userId }); if (!memoryOnly) { @@ -783,20 +793,20 @@ export class CryptoService implements CryptoServiceAbstraction { return phrase; } - private async buildProtectedUserSymKey( - masterKey: MasterKey, - newUserSymKey: ArrayBuffer - ): Promise<[UserSymKey, EncString]> { - let protectedUserSymKey: EncString = null; - if (masterKey.key.byteLength === 32) { - const stretchedMasterKey = await this.stretchKey(masterKey); - protectedUserSymKey = await this.encrypt(newUserSymKey, stretchedMasterKey); - } else if (masterKey.key.byteLength === 64) { - protectedUserSymKey = await this.encrypt(newUserSymKey, masterKey); + private async buildProtectedSymmetricKey( + encryptionKey: SymmetricCryptoKey, + newSymKey: ArrayBuffer + ): Promise<[T, EncString]> { + let protectedSymKey: EncString = null; + if (encryptionKey.key.byteLength === 32) { + const stretchedEncryptionKey = await this.stretchKey(encryptionKey); + protectedSymKey = await this.encrypt(newSymKey, stretchedEncryptionKey); + } else if (encryptionKey.key.byteLength === 64) { + protectedSymKey = await this.encrypt(newSymKey, encryptionKey); } else { throw new Error("Invalid key size."); } - return [new SymmetricCryptoKey(newUserSymKey) as UserSymKey, protectedUserSymKey]; + return [new SymmetricCryptoKey(newSymKey) as T, protectedSymKey]; } private async clearStoredUserKeys(userId?: string): Promise { diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 7258d3a995..4ef864ff0e 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -633,10 +633,10 @@ export class CipherService implements CipherServiceAbstraction { data: ArrayBuffer, admin = false ): Promise { - const key = await this.cryptoService.getOrgKey(cipher.organizationId); - const encFileName = await this.cryptoService.encrypt(filename, key); + const orgKey = await this.cryptoService.getOrgKey(cipher.organizationId); + const encFileName = await this.cryptoService.encrypt(filename, orgKey); - const dataEncKey = await this.cryptoService.makeUserSymKey(key); + const dataEncKey = await this.cryptoService.makeOrgDataEncKey(orgKey); const encData = await this.cryptoService.encryptToBytes(data, dataEncKey[0]); const response = await this.cipherFileUploadService.upload( @@ -946,10 +946,10 @@ export class CipherService implements CipherServiceAbstraction { const encBuf = await EncArrayBuffer.fromResponse(attachmentResponse); const decBuf = await this.cryptoService.decryptFromBytes(encBuf, null); - const key = await this.cryptoService.getOrgKey(organizationId); - const encFileName = await this.cryptoService.encrypt(attachmentView.fileName, key); + const orgKey = await this.cryptoService.getOrgKey(organizationId); + const encFileName = await this.cryptoService.encrypt(attachmentView.fileName, orgKey); - const dataEncKey = await this.cryptoService.makeUserSymKey(key); + const dataEncKey = await this.cryptoService.makeOrgDataEncKey(orgKey); const encData = await this.cryptoService.encryptToBytes(decBuf, dataEncKey[0]); const fd = new FormData();