mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 02:03:39 +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:
102
libs/common/src/platform/services/key-generation.service.spec.ts
Normal file
102
libs/common/src/platform/services/key-generation.service.spec.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { CsprngArray } from "../../types/csprng";
|
||||
import { CryptoFunctionService } from "../abstractions/crypto-function.service";
|
||||
import { KdfType } from "../enums";
|
||||
|
||||
import { KeyGenerationService } from "./key-generation.service";
|
||||
|
||||
describe("KeyGenerationService", () => {
|
||||
let sut: KeyGenerationService;
|
||||
|
||||
const cryptoFunctionService = mock<CryptoFunctionService>();
|
||||
|
||||
beforeEach(() => {
|
||||
sut = new KeyGenerationService(cryptoFunctionService);
|
||||
});
|
||||
|
||||
describe("createKey", () => {
|
||||
test.each([256, 512])(
|
||||
"it should delegate key creation to crypto function service",
|
||||
async (bitLength: 256 | 512) => {
|
||||
cryptoFunctionService.aesGenerateKey
|
||||
.calledWith(bitLength)
|
||||
.mockResolvedValue(new Uint8Array(bitLength / 8) as CsprngArray);
|
||||
|
||||
await sut.createKey(bitLength);
|
||||
|
||||
expect(cryptoFunctionService.aesGenerateKey).toHaveBeenCalledWith(bitLength);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("createMaterialAndKey", () => {
|
||||
test.each([128, 192, 256, 512])(
|
||||
"should create a 64 byte key from different material lengths",
|
||||
async (bitLength: 128 | 192 | 256 | 512) => {
|
||||
const inputMaterial = new Uint8Array(bitLength / 8) as CsprngArray;
|
||||
const inputSalt = "salt";
|
||||
const purpose = "purpose";
|
||||
|
||||
cryptoFunctionService.aesGenerateKey.calledWith(bitLength).mockResolvedValue(inputMaterial);
|
||||
cryptoFunctionService.hkdf
|
||||
.calledWith(inputMaterial, inputSalt, purpose, 64, "sha256")
|
||||
.mockResolvedValue(new Uint8Array(64));
|
||||
|
||||
const { salt, material, derivedKey } = await sut.createKeyWithPurpose(
|
||||
bitLength,
|
||||
purpose,
|
||||
inputSalt,
|
||||
);
|
||||
|
||||
expect(salt).toEqual(inputSalt);
|
||||
expect(material).toEqual(inputMaterial);
|
||||
expect(derivedKey.key.length).toEqual(64);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("deriveKeyFromMaterial", () => {
|
||||
it("should derive a 64 byte key from material", async () => {
|
||||
const material = new Uint8Array(32) as CsprngArray;
|
||||
const salt = "salt";
|
||||
const purpose = "purpose";
|
||||
|
||||
cryptoFunctionService.hkdf.mockResolvedValue(new Uint8Array(64));
|
||||
|
||||
const key = await sut.deriveKeyFromMaterial(material, salt, purpose);
|
||||
|
||||
expect(key.key.length).toEqual(64);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deriveKeyFromPassword", () => {
|
||||
it("should derive a 32 byte key from a password using pbkdf2", async () => {
|
||||
const password = "password";
|
||||
const salt = "salt";
|
||||
const kdf = KdfType.PBKDF2_SHA256;
|
||||
const kdfConfig = new KdfConfig(600_000);
|
||||
|
||||
cryptoFunctionService.pbkdf2.mockResolvedValue(new Uint8Array(32));
|
||||
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdf, kdfConfig);
|
||||
|
||||
expect(key.key.length).toEqual(32);
|
||||
});
|
||||
|
||||
it("should derive a 32 byte key from a password using argon2id", async () => {
|
||||
const password = "password";
|
||||
const salt = "salt";
|
||||
const kdf = KdfType.Argon2id;
|
||||
const kdfConfig = new KdfConfig(600_000, 15);
|
||||
|
||||
cryptoFunctionService.hash.mockResolvedValue(new Uint8Array(32));
|
||||
cryptoFunctionService.argon2.mockResolvedValue(new Uint8Array(32));
|
||||
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdf, kdfConfig);
|
||||
|
||||
expect(key.key.length).toEqual(32);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user