mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 15:28:44 +00:00
Merge pull request #472 from PR0M3TH3AN/codex/add-kdf_iterations-setting-to-configmanager
Support configurable PBKDF2 iterations
This commit is contained in:
@@ -44,6 +44,7 @@ class ConfigManager:
|
||||
"pin_hash": "",
|
||||
"password_hash": "",
|
||||
"inactivity_timeout": INACTIVITY_TIMEOUT,
|
||||
"kdf_iterations": 100_000,
|
||||
"additional_backup_path": "",
|
||||
"secret_mode_enabled": False,
|
||||
"clipboard_clear_delay": 45,
|
||||
@@ -57,6 +58,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("additional_backup_path", "")
|
||||
data.setdefault("secret_mode_enabled", False)
|
||||
data.setdefault("clipboard_clear_delay", 45)
|
||||
@@ -137,6 +139,19 @@ class ConfigManager:
|
||||
config = self.load_config(require_pin=False)
|
||||
return float(config.get("inactivity_timeout", INACTIVITY_TIMEOUT))
|
||||
|
||||
def set_kdf_iterations(self, iterations: int) -> None:
|
||||
"""Persist the PBKDF2 iteration count in the config."""
|
||||
if iterations <= 0:
|
||||
raise ValueError("Iterations must be positive")
|
||||
config = self.load_config(require_pin=False)
|
||||
config["kdf_iterations"] = int(iterations)
|
||||
self.save_config(config)
|
||||
|
||||
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))
|
||||
|
||||
def set_additional_backup_path(self, path: Optional[str]) -> None:
|
||||
"""Persist an optional additional backup path in the config."""
|
||||
config = self.load_config(require_pin=False)
|
||||
|
@@ -381,7 +381,12 @@ class PasswordManager:
|
||||
if password is None:
|
||||
password = prompt_existing_password("Enter your master password: ")
|
||||
|
||||
seed_key = derive_key_from_password(password)
|
||||
iterations = (
|
||||
self.config_manager.get_kdf_iterations()
|
||||
if getattr(self, "config_manager", None)
|
||||
else 100_000
|
||||
)
|
||||
seed_key = derive_key_from_password(password, iterations=iterations)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
try:
|
||||
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||
@@ -428,7 +433,12 @@ class PasswordManager:
|
||||
password = prompt_existing_password("Enter your master password: ")
|
||||
|
||||
try:
|
||||
seed_key = derive_key_from_password(password)
|
||||
iterations = (
|
||||
self.config_manager.get_kdf_iterations()
|
||||
if getattr(self, "config_manager", None)
|
||||
else 100_000
|
||||
)
|
||||
seed_key = derive_key_from_password(password, iterations=iterations)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||
seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate()
|
||||
@@ -572,7 +582,12 @@ class PasswordManager:
|
||||
password = getpass.getpass(prompt="Enter your login password: ").strip()
|
||||
|
||||
# Derive encryption key from password
|
||||
key = derive_key_from_password(password)
|
||||
iterations = (
|
||||
self.config_manager.get_kdf_iterations()
|
||||
if getattr(self, "config_manager", None)
|
||||
else 100_000
|
||||
)
|
||||
key = derive_key_from_password(password, iterations=iterations)
|
||||
|
||||
# Initialize FingerprintManager if not already initialized
|
||||
if not self.fingerprint_manager:
|
||||
@@ -692,7 +707,8 @@ class PasswordManager:
|
||||
# Initialize EncryptionManager with key and fingerprint_dir
|
||||
password = prompt_for_password()
|
||||
index_key = derive_index_key(parent_seed)
|
||||
seed_key = derive_key_from_password(password)
|
||||
iterations = self.config_manager.get_kdf_iterations()
|
||||
seed_key = derive_key_from_password(password, iterations=iterations)
|
||||
|
||||
self.encryption_manager = EncryptionManager(index_key, fingerprint_dir)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
@@ -833,7 +849,12 @@ class PasswordManager:
|
||||
password = prompt_for_password()
|
||||
|
||||
index_key = derive_index_key(seed)
|
||||
seed_key = derive_key_from_password(password)
|
||||
iterations = (
|
||||
self.config_manager.get_kdf_iterations()
|
||||
if getattr(self, "config_manager", None)
|
||||
else 100_000
|
||||
)
|
||||
seed_key = derive_key_from_password(password, iterations=iterations)
|
||||
|
||||
self.encryption_manager = EncryptionManager(index_key, fingerprint_dir)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
@@ -3357,7 +3378,8 @@ class PasswordManager:
|
||||
|
||||
if confirm_action("Encrypt export with a password? (Y/N): "):
|
||||
password = prompt_new_password()
|
||||
key = derive_key_from_password(password)
|
||||
iterations = self.config_manager.get_kdf_iterations()
|
||||
key = derive_key_from_password(password, iterations=iterations)
|
||||
enc_mgr = EncryptionManager(key, dest.parent)
|
||||
data_bytes = enc_mgr.encrypt_data(json_data.encode("utf-8"))
|
||||
dest = dest.with_suffix(dest.suffix + ".enc")
|
||||
@@ -3569,7 +3591,8 @@ class PasswordManager:
|
||||
# Create a new encryption manager with the new password
|
||||
new_key = derive_index_key(self.parent_seed)
|
||||
|
||||
seed_key = derive_key_from_password(new_password)
|
||||
iterations = self.config_manager.get_kdf_iterations()
|
||||
seed_key = derive_key_from_password(new_password, iterations=iterations)
|
||||
seed_mgr = EncryptionManager(seed_key, self.fingerprint_dir)
|
||||
|
||||
new_enc_mgr = EncryptionManager(new_key, self.fingerprint_dir)
|
||||
|
@@ -23,6 +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
|
||||
|
||||
cfg_mgr.set_pin("1234")
|
||||
cfg_mgr.set_relays(["wss://example.com"], require_pin=False)
|
||||
@@ -146,3 +147,14 @@ def test_secret_mode_round_trip():
|
||||
cfg2 = cfg_mgr.load_config(require_pin=False)
|
||||
assert cfg2["secret_mode_enabled"] is True
|
||||
assert cfg2["clipboard_clear_delay"] == 99
|
||||
|
||||
|
||||
def test_kdf_iterations_round_trip():
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
vault, _ = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
|
||||
cfg_mgr = ConfigManager(vault, Path(tmpdir))
|
||||
|
||||
assert cfg_mgr.get_kdf_iterations() == 100_000
|
||||
|
||||
cfg_mgr.set_kdf_iterations(200_000)
|
||||
assert cfg_mgr.get_kdf_iterations() == 200_000
|
||||
|
Reference in New Issue
Block a user