1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-07 19:13:39 +00:00

[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>
This commit is contained in:
Ike
2024-04-25 11:26:01 -07:00
committed by GitHub
parent dba910d0b9
commit 1e4158fd87
82 changed files with 896 additions and 361 deletions

View File

@@ -3,6 +3,7 @@ import { Component, Inject } from "@angular/core";
import { FormGroup, FormControl, Validators } from "@angular/forms";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
import { KdfRequest } from "@bitwarden/common/models/request/kdf.request";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
@@ -18,7 +19,6 @@ import { KdfType } from "@bitwarden/common/platform/enums";
templateUrl: "change-kdf-confirmation.component.html",
})
export class ChangeKdfConfirmationComponent {
kdf: KdfType;
kdfConfig: KdfConfig;
form = new FormGroup({
@@ -37,9 +37,9 @@ export class ChangeKdfConfirmationComponent {
private messagingService: MessagingService,
private stateService: StateService,
private logService: LogService,
@Inject(DIALOG_DATA) params: { kdf: KdfType; kdfConfig: KdfConfig },
private kdfConfigService: KdfConfigService,
@Inject(DIALOG_DATA) params: { kdfConfig: KdfConfig },
) {
this.kdf = params.kdf;
this.kdfConfig = params.kdfConfig;
this.masterPassword = null;
}
@@ -65,22 +65,24 @@ export class ChangeKdfConfirmationComponent {
private async makeKeyAndSaveAsync() {
const masterPassword = this.form.value.masterPassword;
// Ensure the KDF config is valid.
this.kdfConfig.validateKdfConfig();
const request = new KdfRequest();
request.kdf = this.kdf;
request.kdf = this.kdfConfig.kdfType;
request.kdfIterations = this.kdfConfig.iterations;
request.kdfMemory = this.kdfConfig.memory;
request.kdfParallelism = this.kdfConfig.parallelism;
if (this.kdfConfig.kdfType === KdfType.Argon2id) {
request.kdfMemory = this.kdfConfig.memory;
request.kdfParallelism = this.kdfConfig.parallelism;
}
const masterKey = await this.cryptoService.getOrDeriveMasterKey(masterPassword);
request.masterPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey);
const email = await this.stateService.getEmail();
// Ensure the KDF config is valid.
this.cryptoService.validateKdfConfig(this.kdf, this.kdfConfig);
const newMasterKey = await this.cryptoService.makeMasterKey(
masterPassword,
email,
this.kdf,
this.kdfConfig,
);
request.newMasterPasswordHash = await this.cryptoService.hashMasterKey(

View File

@@ -19,14 +19,14 @@
<select
id="kdf"
name="Kdf"
[(ngModel)]="kdf"
[(ngModel)]="kdfConfig.kdfType"
(ngModelChange)="onChangeKdf($event)"
class="form-control mb-3"
required
>
<option *ngFor="let o of kdfOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
<ng-container *ngIf="kdf == kdfType.Argon2id">
<ng-container *ngIf="isArgon2(kdfConfig)">
<label for="kdfMemory">{{ "kdfMemory" | i18n }}</label>
<input
id="kdfMemory"
@@ -43,7 +43,7 @@
</div>
<div class="col-6">
<div class="form-group mb-0">
<ng-container *ngIf="kdf == kdfType.PBKDF2_SHA256">
<ng-container *ngIf="isPBKDF2(kdfConfig)">
<label for="kdfIterations">{{ "kdfIterations" | i18n }}</label>
<a
class="ml-auto"
@@ -65,7 +65,7 @@
required
/>
</ng-container>
<ng-container *ngIf="kdf == kdfType.Argon2id">
<ng-container *ngIf="isArgon2(kdfConfig)">
<label for="kdfIterations">{{ "kdfIterations" | i18n }}</label>
<input
id="iterations"
@@ -92,7 +92,7 @@
</div>
</div>
<div class="col-12">
<ng-container *ngIf="kdf == kdfType.PBKDF2_SHA256">
<ng-container *ngIf="isPBKDF2(kdfConfig)">
<p class="small form-text text-muted">
{{ "kdfIterationsDesc" | i18n: (PBKDF2_ITERATIONS.defaultValue | number) }}
</p>
@@ -100,7 +100,7 @@
{{ "kdfIterationsWarning" | i18n: (100000 | number) }}
</bit-callout>
</ng-container>
<ng-container *ngIf="kdf == kdfType.Argon2id">
<ng-container *ngIf="isArgon2(kdfConfig)">
<p class="small form-text text-muted">{{ "argon2Desc" | i18n }}</p>
<bit-callout type="warning"> {{ "argon2Warning" | i18n }}</bit-callout>
</ng-container>

View File

@@ -1,7 +1,11 @@
import { Component, OnInit } from "@angular/core";
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
import {
Argon2KdfConfig,
KdfConfig,
PBKDF2KdfConfig,
} from "@bitwarden/common/auth/models/domain/kdf-config";
import {
DEFAULT_KDF_CONFIG,
PBKDF2_ITERATIONS,
@@ -19,7 +23,6 @@ import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.compon
templateUrl: "change-kdf.component.html",
})
export class ChangeKdfComponent implements OnInit {
kdf = KdfType.PBKDF2_SHA256;
kdfConfig: KdfConfig = DEFAULT_KDF_CONFIG;
kdfType = KdfType;
kdfOptions: any[] = [];
@@ -31,8 +34,8 @@ export class ChangeKdfComponent implements OnInit {
protected ARGON2_PARALLELISM = ARGON2_PARALLELISM;
constructor(
private stateService: StateService,
private dialogService: DialogService,
private kdfConfigService: KdfConfigService,
) {
this.kdfOptions = [
{ name: "PBKDF2 SHA-256", value: KdfType.PBKDF2_SHA256 },
@@ -41,19 +44,22 @@ export class ChangeKdfComponent implements OnInit {
}
async ngOnInit() {
this.kdf = await this.stateService.getKdfType();
this.kdfConfig = await this.stateService.getKdfConfig();
this.kdfConfig = await this.kdfConfigService.getKdfConfig();
}
isPBKDF2(t: KdfConfig): t is PBKDF2KdfConfig {
return t instanceof PBKDF2KdfConfig;
}
isArgon2(t: KdfConfig): t is Argon2KdfConfig {
return t instanceof Argon2KdfConfig;
}
async onChangeKdf(newValue: KdfType) {
if (newValue === KdfType.PBKDF2_SHA256) {
this.kdfConfig = new KdfConfig(PBKDF2_ITERATIONS.defaultValue);
this.kdfConfig = new PBKDF2KdfConfig();
} else if (newValue === KdfType.Argon2id) {
this.kdfConfig = new KdfConfig(
ARGON2_ITERATIONS.defaultValue,
ARGON2_MEMORY.defaultValue,
ARGON2_PARALLELISM.defaultValue,
);
this.kdfConfig = new Argon2KdfConfig();
} else {
throw new Error("Unknown KDF type.");
}
@@ -62,7 +68,6 @@ export class ChangeKdfComponent implements OnInit {
async openConfirmationModal() {
this.dialogService.open(ChangeKdfConfirmationComponent, {
data: {
kdf: this.kdf,
kdfConfig: this.kdfConfig,
},
});