mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 01:03:35 +00:00
[PM-6211] Create key generation service (#7939)
* create key generation service * replace old key generation service and add references * use key generation service in key connector service * use key generation service in send service * user key generation service in access service * use key generation service in device trust service * fix tests * fix browser * add createKeyFromMaterial and tests * create ephemeral key * fix tests * rename method and add returns docs * ignore material in destructure * modify test * specify material as key material * pull out magic strings to properties * make salt optional and generate if not provided * fix test * fix parameters * update docs to include link to HKDF rfc
This commit is contained in:
@@ -5,11 +5,11 @@ import { CryptoFunctionService } from "../../platform/abstractions/crypto-functi
|
||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
||||
import { I18nService } from "../../platform/abstractions/i18n.service";
|
||||
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
||||
import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "../../platform/abstractions/state.service";
|
||||
import { EncString } from "../../platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key";
|
||||
import { CsprngArray } from "../../types/csprng";
|
||||
import { UserKey, DeviceKey } from "../../types/key";
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction";
|
||||
import { DeviceResponse } from "../abstractions/devices/responses/device.response";
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
|
||||
export class DeviceTrustCryptoService implements DeviceTrustCryptoServiceAbstraction {
|
||||
constructor(
|
||||
private keyGenerationService: KeyGenerationService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private cryptoService: CryptoService,
|
||||
private encryptService: EncryptService,
|
||||
@@ -165,10 +166,7 @@ export class DeviceTrustCryptoService implements DeviceTrustCryptoServiceAbstrac
|
||||
|
||||
private async makeDeviceKey(): Promise<DeviceKey> {
|
||||
// Create 512-bit device key
|
||||
const randomBytes: CsprngArray = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
const deviceKey = new SymmetricCryptoKey(randomBytes) as DeviceKey;
|
||||
|
||||
return deviceKey;
|
||||
return (await this.keyGenerationService.createKey(512)) as DeviceKey;
|
||||
}
|
||||
|
||||
async decryptUserKeyWithDeviceKey(
|
||||
|
||||
@@ -7,6 +7,7 @@ import { CryptoFunctionService } from "../../platform/abstractions/crypto-functi
|
||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
||||
import { I18nService } from "../../platform/abstractions/i18n.service";
|
||||
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
||||
import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "../../platform/abstractions/state.service";
|
||||
import { EncryptionType } from "../../platform/enums/encryption-type.enum";
|
||||
@@ -24,6 +25,7 @@ import { DeviceTrustCryptoService } from "./device-trust-crypto.service.implemen
|
||||
describe("deviceTrustCryptoService", () => {
|
||||
let deviceTrustCryptoService: DeviceTrustCryptoService;
|
||||
|
||||
const keyGenerationService = mock<KeyGenerationService>();
|
||||
const cryptoFunctionService = mock<CryptoFunctionService>();
|
||||
const cryptoService = mock<CryptoService>();
|
||||
const encryptService = mock<EncryptService>();
|
||||
@@ -37,6 +39,7 @@ describe("deviceTrustCryptoService", () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
deviceTrustCryptoService = new DeviceTrustCryptoService(
|
||||
keyGenerationService,
|
||||
cryptoFunctionService,
|
||||
cryptoService,
|
||||
encryptService,
|
||||
@@ -166,17 +169,18 @@ describe("deviceTrustCryptoService", () => {
|
||||
describe("makeDeviceKey", () => {
|
||||
it("creates a new non-null 64 byte device key, securely stores it, and returns it", async () => {
|
||||
const mockRandomBytes = new Uint8Array(deviceKeyBytesLength) as CsprngArray;
|
||||
const mockDeviceKey = new SymmetricCryptoKey(mockRandomBytes) as DeviceKey;
|
||||
|
||||
const cryptoFuncSvcGenerateKeySpy = jest
|
||||
.spyOn(cryptoFunctionService, "aesGenerateKey")
|
||||
.mockResolvedValue(mockRandomBytes);
|
||||
const keyGenSvcGenerateKeySpy = jest
|
||||
.spyOn(keyGenerationService, "createKey")
|
||||
.mockResolvedValue(mockDeviceKey);
|
||||
|
||||
// TypeScript will allow calling private methods if the object is of type 'any'
|
||||
// This is a hacky workaround, but it allows for cleaner tests
|
||||
const deviceKey = await (deviceTrustCryptoService as any).makeDeviceKey();
|
||||
|
||||
expect(cryptoFuncSvcGenerateKeySpy).toHaveBeenCalledTimes(1);
|
||||
expect(cryptoFuncSvcGenerateKeySpy).toHaveBeenCalledWith(deviceKeyBytesLength * 8);
|
||||
expect(keyGenSvcGenerateKeySpy).toHaveBeenCalledTimes(1);
|
||||
expect(keyGenSvcGenerateKeySpy).toHaveBeenCalledWith(deviceKeyBytesLength * 8);
|
||||
|
||||
expect(deviceKey).not.toBeNull();
|
||||
expect(deviceKey).toBeInstanceOf(SymmetricCryptoKey);
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ApiService } from "../../abstractions/api.service";
|
||||
import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserType } from "../../admin-console/enums";
|
||||
import { KeysRequest } from "../../models/request/keys.request";
|
||||
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
||||
import { LogService } from "../../platform/abstractions/log.service";
|
||||
import { StateService } from "../../platform/abstractions/state.service";
|
||||
import { Utils } from "../../platform/misc/utils";
|
||||
@@ -24,7 +24,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
||||
private tokenService: TokenService,
|
||||
private logService: LogService,
|
||||
private organizationService: OrganizationService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private keyGenerationService: KeyGenerationService,
|
||||
private logoutCallback: (expired: boolean, userId?: string) => Promise<void>,
|
||||
) {}
|
||||
|
||||
@@ -94,11 +94,11 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
||||
keyConnectorUrl: legacyKeyConnectorUrl,
|
||||
userDecryptionOptions,
|
||||
} = tokenResponse;
|
||||
const password = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
const password = await this.keyGenerationService.createKey(512);
|
||||
const kdfConfig = new KdfConfig(kdfIterations, kdfMemory, kdfParallelism);
|
||||
|
||||
const masterKey = await this.cryptoService.makeMasterKey(
|
||||
Utils.fromBufferToB64(password),
|
||||
password.keyB64,
|
||||
await this.tokenService.getEmail(),
|
||||
kdf,
|
||||
kdfConfig,
|
||||
|
||||
Reference in New Issue
Block a user