mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 13:53:34 +00:00
[PM-12806] Enforce 5000 iteration minimum for prelogin (#11332)
* Enforce 5000 iteration minimum for prelogin * Fix tests * Add more extensive tests * Add loginstrategy prelogin downgrade test
This commit is contained in:
@@ -61,7 +61,7 @@ export class ChangeKdfConfirmationComponent {
|
|||||||
const masterPassword = this.form.value.masterPassword;
|
const masterPassword = this.form.value.masterPassword;
|
||||||
|
|
||||||
// Ensure the KDF config is valid.
|
// Ensure the KDF config is valid.
|
||||||
this.kdfConfig.validateKdfConfig();
|
this.kdfConfig.validateKdfConfigForSetting();
|
||||||
|
|
||||||
const request = new KdfRequest();
|
const request = new KdfRequest();
|
||||||
request.kdf = this.kdfConfig.kdfType;
|
request.kdf = this.kdfConfig.kdfType;
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"
|
|||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
|
import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
||||||
|
import { PreloginResponse } from "@bitwarden/common/auth/models/response/prelogin.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
@@ -159,6 +161,9 @@ describe("LoginStrategyService", () => {
|
|||||||
new IdentityTokenResponse({
|
new IdentityTokenResponse({
|
||||||
ForcePasswordReset: false,
|
ForcePasswordReset: false,
|
||||||
Kdf: KdfType.Argon2id,
|
Kdf: KdfType.Argon2id,
|
||||||
|
KdfIterations: 2,
|
||||||
|
KdfMemory: 16,
|
||||||
|
KdfParallelism: 1,
|
||||||
Key: "KEY",
|
Key: "KEY",
|
||||||
PrivateKey: "PRIVATE_KEY",
|
PrivateKey: "PRIVATE_KEY",
|
||||||
ResetMasterPassword: false,
|
ResetMasterPassword: false,
|
||||||
@@ -169,6 +174,15 @@ describe("LoginStrategyService", () => {
|
|||||||
token_type: "Bearer",
|
token_type: "Bearer",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
apiService.postPrelogin.mockResolvedValue(
|
||||||
|
new PreloginResponse({
|
||||||
|
Kdf: KdfType.Argon2id,
|
||||||
|
KdfIterations: 2,
|
||||||
|
KdfMemory: 16,
|
||||||
|
KdfParallelism: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
tokenService.decodeAccessToken.calledWith("ACCESS_TOKEN").mockResolvedValue({
|
tokenService.decodeAccessToken.calledWith("ACCESS_TOKEN").mockResolvedValue({
|
||||||
sub: "USER_ID",
|
sub: "USER_ID",
|
||||||
name: "NAME",
|
name: "NAME",
|
||||||
@@ -194,6 +208,15 @@ describe("LoginStrategyService", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
apiService.postPrelogin.mockResolvedValue(
|
||||||
|
new PreloginResponse({
|
||||||
|
Kdf: KdfType.Argon2id,
|
||||||
|
KdfIterations: 2,
|
||||||
|
KdfMemory: 16,
|
||||||
|
KdfParallelism: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
await sut.logIn(credentials);
|
await sut.logIn(credentials);
|
||||||
|
|
||||||
const twoFactorToken = new TokenTwoFactorRequest(
|
const twoFactorToken = new TokenTwoFactorRequest(
|
||||||
@@ -205,6 +228,9 @@ describe("LoginStrategyService", () => {
|
|||||||
new IdentityTokenResponse({
|
new IdentityTokenResponse({
|
||||||
ForcePasswordReset: false,
|
ForcePasswordReset: false,
|
||||||
Kdf: KdfType.Argon2id,
|
Kdf: KdfType.Argon2id,
|
||||||
|
KdfIterations: 2,
|
||||||
|
KdfMemory: 16,
|
||||||
|
KdfParallelism: 1,
|
||||||
Key: "KEY",
|
Key: "KEY",
|
||||||
PrivateKey: "PRIVATE_KEY",
|
PrivateKey: "PRIVATE_KEY",
|
||||||
ResetMasterPassword: false,
|
ResetMasterPassword: false,
|
||||||
@@ -241,6 +267,15 @@ describe("LoginStrategyService", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
apiService.postPrelogin.mockResolvedValue(
|
||||||
|
new PreloginResponse({
|
||||||
|
Kdf: KdfType.Argon2id,
|
||||||
|
KdfIterations: 2,
|
||||||
|
KdfMemory: 16,
|
||||||
|
KdfParallelism: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
await sut.logIn(credentials);
|
await sut.logIn(credentials);
|
||||||
|
|
||||||
loginStrategyCacheExpirationState.stateSubject.next(new Date(Date.now() - 1000 * 60 * 5));
|
loginStrategyCacheExpirationState.stateSubject.next(new Date(Date.now() - 1000 * 60 * 5));
|
||||||
@@ -253,4 +288,40 @@ describe("LoginStrategyService", () => {
|
|||||||
|
|
||||||
await expect(sut.logInTwoFactor(twoFactorToken, "CAPTCHA")).rejects.toThrow();
|
await expect(sut.logInTwoFactor(twoFactorToken, "CAPTCHA")).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throw error on too low kdf config", async () => {
|
||||||
|
const credentials = new PasswordLoginCredentials("EMAIL", "MASTER_PASSWORD");
|
||||||
|
apiService.postIdentityToken.mockResolvedValue(
|
||||||
|
new IdentityTokenResponse({
|
||||||
|
ForcePasswordReset: false,
|
||||||
|
Kdf: KdfType.PBKDF2_SHA256,
|
||||||
|
KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1,
|
||||||
|
Key: "KEY",
|
||||||
|
PrivateKey: "PRIVATE_KEY",
|
||||||
|
ResetMasterPassword: false,
|
||||||
|
access_token: "ACCESS_TOKEN",
|
||||||
|
expires_in: 3600,
|
||||||
|
refresh_token: "REFRESH_TOKEN",
|
||||||
|
scope: "api offline_access",
|
||||||
|
token_type: "Bearer",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
apiService.postPrelogin.mockResolvedValue(
|
||||||
|
new PreloginResponse({
|
||||||
|
Kdf: KdfType.PBKDF2_SHA256,
|
||||||
|
KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenService.decodeAccessToken.calledWith("ACCESS_TOKEN").mockResolvedValue({
|
||||||
|
sub: "USER_ID",
|
||||||
|
name: "NAME",
|
||||||
|
email: "EMAIL",
|
||||||
|
premium: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(sut.logIn(credentials)).rejects.toThrow(
|
||||||
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -264,6 +264,9 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kdfConfig.validateKdfConfigForPrelogin();
|
||||||
|
|
||||||
return await this.cryptoService.makeMasterKey(masterPassword, email, kdfConfig);
|
return await this.cryptoService.makeMasterKey(masterPassword, email, kdfConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type KdfConfig = PBKDF2KdfConfig | Argon2KdfConfig;
|
|||||||
*/
|
*/
|
||||||
export class PBKDF2KdfConfig {
|
export class PBKDF2KdfConfig {
|
||||||
static ITERATIONS = new RangeWithDefault(600_000, 2_000_000, 600_000);
|
static ITERATIONS = new RangeWithDefault(600_000, 2_000_000, 600_000);
|
||||||
|
static PRELOGIN_ITERATIONS = new RangeWithDefault(5000, 2_000_000, 600_000);
|
||||||
kdfType: KdfType.PBKDF2_SHA256 = KdfType.PBKDF2_SHA256;
|
kdfType: KdfType.PBKDF2_SHA256 = KdfType.PBKDF2_SHA256;
|
||||||
iterations: number;
|
iterations: number;
|
||||||
|
|
||||||
@@ -21,10 +22,10 @@ export class PBKDF2KdfConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the PBKDF2 KDF configuration.
|
* Validates the PBKDF2 KDF configuration for updating the KDF config.
|
||||||
* A Valid PBKDF2 KDF configuration has KDF iterations between the 600_000 and 2_000_000.
|
* A Valid PBKDF2 KDF configuration has KDF iterations between the 600_000 and 2_000_000.
|
||||||
*/
|
*/
|
||||||
validateKdfConfig(): void {
|
validateKdfConfigForSetting(): void {
|
||||||
if (!PBKDF2KdfConfig.ITERATIONS.inRange(this.iterations)) {
|
if (!PBKDF2KdfConfig.ITERATIONS.inRange(this.iterations)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.ITERATIONS.min} and ${PBKDF2KdfConfig.ITERATIONS.max}`,
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.ITERATIONS.min} and ${PBKDF2KdfConfig.ITERATIONS.max}`,
|
||||||
@@ -32,6 +33,18 @@ export class PBKDF2KdfConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the PBKDF2 KDF configuration for pre-login.
|
||||||
|
* A Valid PBKDF2 KDF configuration has KDF iterations between the 5000 and 2_000_000.
|
||||||
|
*/
|
||||||
|
validateKdfConfigForPrelogin(): void {
|
||||||
|
if (!PBKDF2KdfConfig.PRELOGIN_ITERATIONS.inRange(this.iterations)) {
|
||||||
|
throw new Error(
|
||||||
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static fromJSON(json: Jsonify<PBKDF2KdfConfig>): PBKDF2KdfConfig {
|
static fromJSON(json: Jsonify<PBKDF2KdfConfig>): PBKDF2KdfConfig {
|
||||||
return new PBKDF2KdfConfig(json.iterations);
|
return new PBKDF2KdfConfig(json.iterations);
|
||||||
}
|
}
|
||||||
@@ -44,6 +57,11 @@ export class Argon2KdfConfig {
|
|||||||
static MEMORY = new RangeWithDefault(16, 1024, 64);
|
static MEMORY = new RangeWithDefault(16, 1024, 64);
|
||||||
static PARALLELISM = new RangeWithDefault(1, 16, 4);
|
static PARALLELISM = new RangeWithDefault(1, 16, 4);
|
||||||
static ITERATIONS = new RangeWithDefault(2, 10, 3);
|
static ITERATIONS = new RangeWithDefault(2, 10, 3);
|
||||||
|
|
||||||
|
static PRELOGIN_MEMORY = Argon2KdfConfig.MEMORY;
|
||||||
|
static PRELOGIN_PARALLELISM = Argon2KdfConfig.PARALLELISM;
|
||||||
|
static PRELOGIN_ITERATIONS = Argon2KdfConfig.ITERATIONS;
|
||||||
|
|
||||||
kdfType: KdfType.Argon2id = KdfType.Argon2id;
|
kdfType: KdfType.Argon2id = KdfType.Argon2id;
|
||||||
iterations: number;
|
iterations: number;
|
||||||
memory: number;
|
memory: number;
|
||||||
@@ -56,10 +74,10 @@ export class Argon2KdfConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the Argon2 KDF configuration.
|
* Validates the Argon2 KDF configuration for updating the KDF config.
|
||||||
* A Valid Argon2 KDF configuration has iterations between 2 and 10, memory between 16mb and 1024mb, and parallelism between 1 and 16.
|
* A Valid Argon2 KDF configuration has iterations between 2 and 10, memory between 16mb and 1024mb, and parallelism between 1 and 16.
|
||||||
*/
|
*/
|
||||||
validateKdfConfig(): void {
|
validateKdfConfigForSetting(): void {
|
||||||
if (!Argon2KdfConfig.ITERATIONS.inRange(this.iterations)) {
|
if (!Argon2KdfConfig.ITERATIONS.inRange(this.iterations)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
||||||
@@ -79,6 +97,29 @@ export class Argon2KdfConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the Argon2 KDF configuration for pre-login.
|
||||||
|
*/
|
||||||
|
validateKdfConfigForPrelogin(): void {
|
||||||
|
if (!Argon2KdfConfig.PRELOGIN_ITERATIONS.inRange(this.iterations)) {
|
||||||
|
throw new Error(
|
||||||
|
`Argon2 iterations must be between ${Argon2KdfConfig.PRELOGIN_ITERATIONS.min} and ${Argon2KdfConfig.PRELOGIN_ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Argon2KdfConfig.PRELOGIN_MEMORY.inRange(this.memory)) {
|
||||||
|
throw new Error(
|
||||||
|
`Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Argon2KdfConfig.PRELOGIN_PARALLELISM.inRange(this.parallelism)) {
|
||||||
|
throw new Error(
|
||||||
|
`Argon2 parallelism must be between ${Argon2KdfConfig.PRELOGIN_PARALLELISM.min} and ${Argon2KdfConfig.PRELOGIN_PARALLELISM.max}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static fromJSON(json: Jsonify<Argon2KdfConfig>): Argon2KdfConfig {
|
static fromJSON(json: Jsonify<Argon2KdfConfig>): Argon2KdfConfig {
|
||||||
return new Argon2KdfConfig(json.iterations, json.memory, json.parallelism);
|
return new Argon2KdfConfig(json.iterations, json.memory, json.parallelism);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,41 +58,120 @@ describe("KdfConfigService", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should validate the PBKDF2 KDF config", () => {
|
it("validateKdfConfigForSetting(): should validate the PBKDF2 KDF config", () => {
|
||||||
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(600_000);
|
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(600_000);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).not.toThrow();
|
expect(() => kdfConfig.validateKdfConfigForSetting()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should validate the Argon2id KDF config", () => {
|
it("validateKdfConfigForSetting(): should validate the Argon2id KDF config", () => {
|
||||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).not.toThrow();
|
expect(() => kdfConfig.validateKdfConfigForSetting()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should throw an error for invalid PBKDF2 iterations", () => {
|
it("validateKdfConfigForSetting(): should throw an error for invalid PBKDF2 iterations", () => {
|
||||||
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(100);
|
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(100000);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow(
|
||||||
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.ITERATIONS.min} and ${PBKDF2KdfConfig.ITERATIONS.max}`,
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.ITERATIONS.min} and ${PBKDF2KdfConfig.ITERATIONS.max}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should throw an error for invalid Argon2 iterations", () => {
|
it("validateKdfConfigForSetting(): should throw an error for invalid Argon2 iterations", () => {
|
||||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(11, 64, 4);
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(11, 64, 4);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow(
|
||||||
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should throw an error for invalid Argon2 memory", () => {
|
it("validateKdfConfigForSetting(): should throw an error for invalid Argon2 memory", () => {
|
||||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 1025, 4);
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 1025, 4);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow(
|
||||||
`Argon2 memory must be between ${Argon2KdfConfig.MEMORY.min}mb and ${Argon2KdfConfig.MEMORY.max}mb`,
|
`Argon2 memory must be between ${Argon2KdfConfig.MEMORY.min}mb and ${Argon2KdfConfig.MEMORY.max}mb`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validateKdfConfig(): should throw an error for invalid Argon2 parallelism", () => {
|
it("validateKdfConfigForSetting(): should throw an error for invalid Argon2 parallelism", () => {
|
||||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17);
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17);
|
||||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow(
|
||||||
`Argon2 parallelism must be between ${Argon2KdfConfig.PARALLELISM.min} and ${Argon2KdfConfig.PARALLELISM.max}`,
|
`Argon2 parallelism must be between ${Argon2KdfConfig.PARALLELISM.min} and ${Argon2KdfConfig.PARALLELISM.max}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should validate the PBKDF2 KDF config", () => {
|
||||||
|
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(600_000);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should validate the Argon2id KDF config", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too low PBKDF2 iterations", () => {
|
||||||
|
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(
|
||||||
|
PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too high PBKDF2 iterations", () => {
|
||||||
|
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(
|
||||||
|
PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max + 1,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too low Argon2 iterations", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(
|
||||||
|
Argon2KdfConfig.ITERATIONS.min - 1,
|
||||||
|
64,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 iterations", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(
|
||||||
|
Argon2KdfConfig.PRELOGIN_ITERATIONS.max + 1,
|
||||||
|
64,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too low Argon2 memory", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(
|
||||||
|
3,
|
||||||
|
Argon2KdfConfig.PRELOGIN_MEMORY.min - 1,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 memory", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(
|
||||||
|
3,
|
||||||
|
Argon2KdfConfig.PRELOGIN_MEMORY.max + 1,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 parallelism", () => {
|
||||||
|
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17);
|
||||||
|
expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow(
|
||||||
|
`Argon2 parallelism must be between ${Argon2KdfConfig.PRELOGIN_PARALLELISM.min} and ${Argon2KdfConfig.PRELOGIN_PARALLELISM.max}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user