1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-09 20:13:42 +00:00
Files
browser/libs/common/src/platform/services/key-generation.service.ts
Ike 1e4158fd87 [PM-5735] Create kdf Service (#8715)
* key connector migration initial

* migrator complete

* fix dependencies

* finalized tests

* fix deps and sync main

* clean up definition file

* fixing tests

* fixed tests

* fixing CLI, Browser, Desktop builds

* fixed factory options

* reverting exports

* implemented UserKeyDefinition clearOn

* Initial Kdf Service Changes

* rename and account setting kdfconfig

* fixing tests and renaming migration

* fixed DI ordering for browser

* rename and fix DI

* Clean up Migrations

* fixing migrations

* begin data structure changes for kdf config

* Make KDF more type safe; co-author: jlf0dev

* fixing tests

* Fixed CLI login and comments

* set now accepts userId and test updates

---------

Co-authored-by: Jake Fink <jfink@bitwarden.com>
2024-04-25 11:26:01 -07:00

85 lines
3.0 KiB
TypeScript

import { KdfConfig } from "../../auth/models/domain/kdf-config";
import { CsprngArray } from "../../types/csprng";
import { CryptoFunctionService } from "../abstractions/crypto-function.service";
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "../abstractions/key-generation.service";
import {
ARGON2_ITERATIONS,
ARGON2_MEMORY,
ARGON2_PARALLELISM,
KdfType,
PBKDF2_ITERATIONS,
} from "../enums";
import { Utils } from "../misc/utils";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
export class KeyGenerationService implements KeyGenerationServiceAbstraction {
constructor(private cryptoFunctionService: CryptoFunctionService) {}
async createKey(bitLength: 256 | 512): Promise<SymmetricCryptoKey> {
const key = await this.cryptoFunctionService.aesGenerateKey(bitLength);
return new SymmetricCryptoKey(key);
}
async createKeyWithPurpose(
bitLength: 128 | 192 | 256 | 512,
purpose: string,
salt?: string,
): Promise<{ salt: string; material: CsprngArray; derivedKey: SymmetricCryptoKey }> {
if (salt == null) {
const bytes = await this.cryptoFunctionService.randomBytes(32);
salt = Utils.fromBufferToUtf8(bytes);
}
const material = await this.cryptoFunctionService.aesGenerateKey(bitLength);
const key = await this.cryptoFunctionService.hkdf(material, salt, purpose, 64, "sha256");
return { salt, material, derivedKey: new SymmetricCryptoKey(key) };
}
async deriveKeyFromMaterial(
material: CsprngArray,
salt: string,
purpose: string,
): Promise<SymmetricCryptoKey> {
const key = await this.cryptoFunctionService.hkdf(material, salt, purpose, 64, "sha256");
return new SymmetricCryptoKey(key);
}
async deriveKeyFromPassword(
password: string | Uint8Array,
salt: string | Uint8Array,
kdfConfig: KdfConfig,
): Promise<SymmetricCryptoKey> {
let key: Uint8Array = null;
if (kdfConfig.kdfType == null || kdfConfig.kdfType === KdfType.PBKDF2_SHA256) {
if (kdfConfig.iterations == null) {
kdfConfig.iterations = PBKDF2_ITERATIONS.defaultValue;
}
key = await this.cryptoFunctionService.pbkdf2(password, salt, "sha256", kdfConfig.iterations);
} else if (kdfConfig.kdfType == KdfType.Argon2id) {
if (kdfConfig.iterations == null) {
kdfConfig.iterations = ARGON2_ITERATIONS.defaultValue;
}
if (kdfConfig.memory == null) {
kdfConfig.memory = ARGON2_MEMORY.defaultValue;
}
if (kdfConfig.parallelism == null) {
kdfConfig.parallelism = ARGON2_PARALLELISM.defaultValue;
}
const saltHash = await this.cryptoFunctionService.hash(salt, "sha256");
key = await this.cryptoFunctionService.argon2(
password,
saltHash,
kdfConfig.iterations,
kdfConfig.memory * 1024, // convert to KiB from MiB
kdfConfig.parallelism,
);
} else {
throw new Error("Unknown Kdf.");
}
return new SymmetricCryptoKey(key);
}
}