mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-07 14:58:56 +00:00
Add Hypothesis fuzz test for EncryptionManager
This commit is contained in:
@@ -423,6 +423,11 @@ pip install -r src/requirements.txt
|
||||
pytest -vv
|
||||
```
|
||||
|
||||
`test_fuzz_key_derivation.py` uses Hypothesis to generate random passwords,
|
||||
seeds and configuration data. It performs round-trip encryption tests with the
|
||||
`EncryptionManager` to catch edge cases automatically. These fuzz tests run in
|
||||
CI alongside the rest of the suite.
|
||||
|
||||
### Exploring Nostr Index Size Limits
|
||||
|
||||
`test_nostr_index_size.py` demonstrates how SeedPass rotates snapshots after too many delta events.
|
||||
|
63
src/tests/test_fuzz_key_derivation.py
Normal file
63
src/tests/test_fuzz_key_derivation.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from hypothesis import given, strategies as st, settings, HealthCheck
|
||||
from mnemonic import Mnemonic
|
||||
|
||||
from utils.key_derivation import (
|
||||
derive_key_from_password,
|
||||
derive_key_from_password_argon2,
|
||||
derive_index_key,
|
||||
)
|
||||
from password_manager.encryption import EncryptionManager
|
||||
|
||||
|
||||
cfg_values = st.one_of(
|
||||
st.integers(min_value=0, max_value=100),
|
||||
st.text(min_size=0, max_size=20),
|
||||
st.booleans(),
|
||||
)
|
||||
|
||||
|
||||
@given(
|
||||
password=st.text(min_size=8, max_size=32),
|
||||
seed_bytes=st.binary(min_size=16, max_size=16),
|
||||
config=st.dictionaries(st.text(min_size=1, max_size=10), cfg_values, max_size=5),
|
||||
mode=st.sampled_from(["pbkdf2", "argon2"]),
|
||||
)
|
||||
@settings(
|
||||
deadline=None,
|
||||
max_examples=20,
|
||||
suppress_health_check=[HealthCheck.function_scoped_fixture],
|
||||
)
|
||||
def test_fuzz_key_round_trip(password, seed_bytes, config, mode, tmp_path: Path):
|
||||
"""Ensure EncryptionManager round-trips arbitrary data."""
|
||||
seed_phrase = Mnemonic("english").to_mnemonic(seed_bytes)
|
||||
if mode == "argon2":
|
||||
key = derive_key_from_password_argon2(
|
||||
password, time_cost=1, memory_cost=8, parallelism=1
|
||||
)
|
||||
else:
|
||||
key = derive_key_from_password(password, iterations=1)
|
||||
|
||||
enc_mgr = EncryptionManager(key, tmp_path)
|
||||
|
||||
# Parent seed round trip
|
||||
enc_mgr.encrypt_parent_seed(seed_phrase)
|
||||
assert enc_mgr.decrypt_parent_seed() == seed_phrase
|
||||
|
||||
# JSON data round trip
|
||||
enc_mgr.save_json_data(config, Path("config.enc"))
|
||||
loaded = enc_mgr.load_json_data(Path("config.enc"))
|
||||
assert loaded == config
|
||||
|
||||
# Binary data round trip
|
||||
blob = os.urandom(32)
|
||||
enc_mgr.encrypt_and_save_file(blob, Path("blob.enc"))
|
||||
assert enc_mgr.decrypt_file(Path("blob.enc")) == blob
|
||||
|
||||
# Index key derived from seed also decrypts
|
||||
index_key = derive_index_key(seed_phrase)
|
||||
idx_mgr = EncryptionManager(index_key, tmp_path)
|
||||
idx_mgr.save_json_data(config)
|
||||
assert idx_mgr.load_json_data() == config
|
Reference in New Issue
Block a user