1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-26 13:13:22 +00:00

[PM-22271] Switch to SDK argon2 implementation, and drop other impls (#15401)

* Switch to SDK argon2 implementation

* Cleanup and update to the latest sdk

* Update package lock

* Remove copy patch

* Fix builds

* Fix test build

* Remove error

* Fix tests

* Fix build

* Run prettier

* Remove argon2 references

* Regenerate index.d.ts for desktop_native napi

* Replace mocked crypto function service type
This commit is contained in:
Bernd Schoolmann
2025-07-15 11:53:58 +02:00
committed by GitHub
parent 1315e7c37c
commit 8250e40c6c
27 changed files with 44 additions and 697 deletions

View File

@@ -6,6 +6,7 @@ import { PBKDF2KdfConfig, Argon2KdfConfig } from "@bitwarden/key-management";
import { CryptoFunctionService } from "../../key-management/crypto/abstractions/crypto-function.service";
import { CsprngArray } from "../../types/csprng";
import { SdkLoadService } from "../abstractions/sdk/sdk-load.service";
import { EncryptionType } from "../enums";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
@@ -77,27 +78,30 @@ describe("KeyGenerationService", () => {
describe("deriveKeyFromPassword", () => {
it("should derive a 32 byte key from a password using pbkdf2", async () => {
const password = "password";
const salt = "salt";
const password = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const salt = new Uint8Array([9, 10, 11, 12]);
const kdfConfig = new PBKDF2KdfConfig(600_000);
cryptoFunctionService.pbkdf2.mockResolvedValue(new Uint8Array(32));
Object.defineProperty(SdkLoadService, "Ready", {
value: Promise.resolve(),
configurable: true,
});
const key = await sut.deriveKeyFromPassword(password, salt, kdfConfig);
expect(key.inner().type).toEqual(EncryptionType.AesCbc256_B64);
});
it("should derive a 32 byte key from a password using argon2id", async () => {
const password = "password";
const salt = "salt";
const password = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const salt = new Uint8Array([9, 10, 11, 12]);
const kdfConfig = new Argon2KdfConfig(3, 16, 4);
cryptoFunctionService.hash.mockResolvedValue(new Uint8Array(32));
cryptoFunctionService.argon2.mockResolvedValue(new Uint8Array(32));
Object.defineProperty(SdkLoadService, "Ready", {
value: Promise.resolve(),
configurable: true,
});
const key = await sut.deriveKeyFromPassword(password, salt, kdfConfig);
expect(key.inner().type).toEqual(EncryptionType.AesCbc256_B64);
});
});

View File

@@ -2,11 +2,13 @@
// @ts-strict-ignore
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
// eslint-disable-next-line no-restricted-imports
import { KdfConfig, PBKDF2KdfConfig, Argon2KdfConfig, KdfType } from "@bitwarden/key-management";
import { KdfConfig } from "@bitwarden/key-management";
import { PureCrypto } from "@bitwarden/sdk-internal";
import { CryptoFunctionService } from "../../key-management/crypto/abstractions/crypto-function.service";
import { CsprngArray } from "../../types/csprng";
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "../abstractions/key-generation.service";
import { SdkLoadService } from "../abstractions/sdk/sdk-load.service";
import { EncryptionType } from "../enums";
import { Utils } from "../misc/utils";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
@@ -47,38 +49,17 @@ export class KeyGenerationService implements KeyGenerationServiceAbstraction {
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 = PBKDF2KdfConfig.ITERATIONS.defaultValue;
}
key = await this.cryptoFunctionService.pbkdf2(password, salt, "sha256", kdfConfig.iterations);
} else if (kdfConfig.kdfType == KdfType.Argon2id) {
if (kdfConfig.iterations == null) {
kdfConfig.iterations = Argon2KdfConfig.ITERATIONS.defaultValue;
}
if (kdfConfig.memory == null) {
kdfConfig.memory = Argon2KdfConfig.MEMORY.defaultValue;
}
if (kdfConfig.parallelism == null) {
kdfConfig.parallelism = Argon2KdfConfig.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.");
if (typeof password === "string") {
password = new TextEncoder().encode(password);
}
return new SymmetricCryptoKey(key);
if (typeof salt === "string") {
salt = new TextEncoder().encode(salt);
}
await SdkLoadService.Ready;
return new SymmetricCryptoKey(
PureCrypto.derive_kdf_material(password, salt, kdfConfig.toSdkConfig()),
);
}
async stretchKey(key: SymmetricCryptoKey): Promise<SymmetricCryptoKey> {