1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-04-06 18:47:05 +02:00

add org key type and new method to build a data enc key for orgs

This commit is contained in:
Jacob Fink 2023-06-09 10:30:24 -04:00
parent 2789fdc393
commit 8353d67e1f
No known key found for this signature in database
GPG Key ID: C2F7ACF05859D008
4 changed files with 42 additions and 25 deletions

View File

@ -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<SymmetricCryptoKey>;
getOrgKey: (orgId: string) => Promise<OrgKey>;
/**
* @returns A map of the organization Ids to their symmetric keys
*/
getOrgKeys: () => Promise<Map<string, SymmetricCryptoKey>>;
/**
* 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

View File

@ -81,3 +81,4 @@ export type DeviceKey = Opaque<SymmetricCryptoKey, "DeviceKey">;
export type UserSymKey = Opaque<SymmetricCryptoKey, "UserSymKey">;
export type MasterKey = Opaque<SymmetricCryptoKey, "MasterKey">;
export type PinKey = Opaque<SymmetricCryptoKey, "PinKey">;
export type OrgKey = Opaque<SymmetricCryptoKey, "OrgKey">;

View File

@ -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<void> {
@ -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<SymmetricCryptoKey> {
async getOrgKey(orgId: string): Promise<OrgKey> {
if (orgId == null) {
return null;
}
@ -285,11 +286,11 @@ export class CryptoService implements CryptoServiceAbstraction {
}
@sequentialize(() => "getOrgKeys")
async getOrgKeys(): Promise<Map<string, SymmetricCryptoKey>> {
const result: Map<string, SymmetricCryptoKey> = new Map<string, SymmetricCryptoKey>();
async getOrgKeys(): Promise<Map<string, OrgKey>> {
const result: Map<string, OrgKey> = new Map<string, OrgKey>();
const decryptedOrganizationKeys = await this.stateService.getDecryptedOrganizationKeys();
if (decryptedOrganizationKeys != null && decryptedOrganizationKeys.size > 0) {
return decryptedOrganizationKeys;
return decryptedOrganizationKeys as Map<string, OrgKey>;
}
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<void> {
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<T extends SymmetricCryptoKey>(
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<void> {

View File

@ -633,10 +633,10 @@ export class CipherService implements CipherServiceAbstraction {
data: ArrayBuffer,
admin = false
): Promise<Cipher> {
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();