From 96d5a1bb5773021f31d15e448a6a2c60dc5de1ed Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 13 Jul 2025 14:40:15 -0400 Subject: [PATCH] Lower KDF iteration default --- README.md | 3 ++- docs/docs/content/index.md | 1 + src/password_manager/config_manager.py | 6 +++--- src/password_manager/manager.py | 10 +++++----- src/tests/test_config_manager.py | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 535523f..e3d1e70 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,7 @@ seedpass config set kdf_iterations 200000 seedpass config set backup_interval 3600 ``` -Lower iteration counts speed up vault decryption but make brute-force attacks easier. A long backup interval means fewer backups and increases the risk of data loss. +The default configuration uses **50,000** PBKDF2 iterations. Lower iteration counts speed up vault decryption but make brute-force attacks easier. A long backup interval means fewer backups and increases the risk of data loss. ## Running Tests @@ -485,6 +485,7 @@ Mutation testing is disabled in the GitHub workflow due to reliability issues an - **Potential Bugs and Limitations:** Be aware that the software may contain bugs and lacks certain features. Snapshot chunks are capped at 50 KB and the client rotates snapshots after enough delta events accumulate. The security of memory management and logs has not been thoroughly evaluated and may pose risks of leaking sensitive information. - **Multiple Seeds Management:** While managing multiple seeds adds flexibility, it also increases the responsibility to secure each seed and its associated password. - **No PBKDF2 Salt Required:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. +- **Default KDF Iterations:** New profiles start with 50,000 PBKDF2 iterations. Adjust this with `seedpass config set kdf_iterations`. - **KDF Iteration Caution:** Lowering `kdf_iterations` makes password cracking easier, while a high `backup_interval` leaves fewer recent backups. ## Contributing diff --git a/docs/docs/content/index.md b/docs/docs/content/index.md index 66c3069..ef46fa5 100644 --- a/docs/docs/content/index.md +++ b/docs/docs/content/index.md @@ -494,6 +494,7 @@ Mutation testing is disabled in the GitHub workflow due to reliability issues an - **Potential Bugs and Limitations:** Be aware that the software may contain bugs and lacks certain features. Snapshot chunks are capped at 50 KB and the client rotates snapshots after enough delta events accumulate. The security of memory management and logs has not been thoroughly evaluated and may pose risks of leaking sensitive information. - **Multiple Seeds Management:** While managing multiple seeds adds flexibility, it also increases the responsibility to secure each seed and its associated password. - **No PBKDF2 Salt Required:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. +- **Default KDF Iterations:** New profiles start with 50,000 PBKDF2 iterations. Use `seedpass config set kdf_iterations` to change this. ## Contributing diff --git a/src/password_manager/config_manager.py b/src/password_manager/config_manager.py index da02273..c3bba67 100644 --- a/src/password_manager/config_manager.py +++ b/src/password_manager/config_manager.py @@ -45,7 +45,7 @@ class ConfigManager: "pin_hash": "", "password_hash": "", "inactivity_timeout": INACTIVITY_TIMEOUT, - "kdf_iterations": 100_000, + "kdf_iterations": 50_000, "kdf_mode": "pbkdf2", "additional_backup_path": "", "backup_interval": 0, @@ -66,7 +66,7 @@ class ConfigManager: data.setdefault("pin_hash", "") data.setdefault("password_hash", "") data.setdefault("inactivity_timeout", INACTIVITY_TIMEOUT) - data.setdefault("kdf_iterations", 100_000) + data.setdefault("kdf_iterations", 50_000) data.setdefault("kdf_mode", "pbkdf2") data.setdefault("additional_backup_path", "") data.setdefault("backup_interval", 0) @@ -165,7 +165,7 @@ class ConfigManager: def get_kdf_iterations(self) -> int: """Retrieve the PBKDF2 iteration count.""" config = self.load_config(require_pin=False) - return int(config.get("kdf_iterations", 100_000)) + return int(config.get("kdf_iterations", 50_000)) def set_kdf_mode(self, mode: str) -> None: """Persist the key derivation function mode.""" diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 451d71d..e74b1e5 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -397,7 +397,7 @@ class PasswordManager: iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) - else 100_000 + else 50_000 ) print("Deriving key...") if mode == "argon2": @@ -466,7 +466,7 @@ class PasswordManager: iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) - else 100_000 + else 50_000 ) if mode == "argon2": seed_key = derive_key_from_password_argon2(password) @@ -618,7 +618,7 @@ class PasswordManager: iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) - else 100_000 + else 50_000 ) key = derive_key_from_password(password, iterations=iterations) @@ -744,7 +744,7 @@ class PasswordManager: iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) - else 100_000 + else 50_000 ) seed_key = derive_key_from_password(password, iterations=iterations) @@ -901,7 +901,7 @@ class PasswordManager: iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) - else 100_000 + else 50_000 ) seed_key = derive_key_from_password(password, iterations=iterations) diff --git a/src/tests/test_config_manager.py b/src/tests/test_config_manager.py index 799ea84..9402bb8 100644 --- a/src/tests/test_config_manager.py +++ b/src/tests/test_config_manager.py @@ -23,7 +23,7 @@ def test_config_defaults_and_round_trip(): assert cfg["pin_hash"] == "" assert cfg["password_hash"] == "" assert cfg["additional_backup_path"] == "" - assert cfg["kdf_iterations"] == 100_000 + assert cfg["kdf_iterations"] == 50_000 cfg_mgr.set_pin("1234") cfg_mgr.set_relays(["wss://example.com"], require_pin=False) @@ -154,7 +154,7 @@ def test_kdf_iterations_round_trip(): vault, _ = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD) cfg_mgr = ConfigManager(vault, Path(tmpdir)) - assert cfg_mgr.get_kdf_iterations() == 100_000 + assert cfg_mgr.get_kdf_iterations() == 50_000 cfg_mgr.set_kdf_iterations(200_000) assert cfg_mgr.get_kdf_iterations() == 200_000