mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-11-08 05:42:27 +00:00
Offer a 24-word master seed, and put the entropy draw beyond reach of any handler
L2: generate_bip85_seed and create_profile_from_generated_seed now take words_num, accepting 12 or 24 and rejecting anything else with a clear message. The default stays 12 -- every existing profile uses it, 128 bits is entirely adequate, and moving the default would change nothing about existing vaults while surprising anyone creating a new one. 24 is offered because the master seed protects the whole vault and was the one secret shorter than the seeds derived beneath it, which already default to 24. L3: fixed structurally rather than by narrowing exception types. os.urandom(32) now sits OUTSIDE the try block, so no handler can stand between the entropy draw and the caller -- an entropy failure is unreachable by anything that could substitute a value. Also removes a redundant `except Exception` whose body was identical to the `Bip85Error` branch above it. The structural form is stronger than an exception list, and the test says so precisely: it asserts the OSError reaching the caller is the SAME OBJECT os.urandom threw, which holds only if nothing caught and repackaged it. Listing exception types would still leave a handler in the path for someone to widen later. Adds five tests: the identity assertion above, 12- and 24-word generation, the default staying 12, and rejection of 0/11/18/25/-12. Determinism gate green (89 tests, up from 84). The seed/profile regression subset is 143 passed with one failure -- test_profile_export_import_round_trip -- confirmed against the pre-change baseline as pre-existing. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
This commit is contained in:
1 parent
6ac40d2e15
commit
3192c9f306
5 files changed
+138
-17
No files matched your search
@@ -191,6 +191,56 @@ def test_seed_generation_aborts_on_short_read(monkeypatch):
|
||||
manager_module.PasswordManager.generate_bip85_seed(object())
|
||||
|
||||
|
||||
def test_entropy_draw_sits_outside_the_try_block(monkeypatch):
|
||||
"""L3: no except clause may stand between os.urandom and the caller.
|
||||
|
||||
The generator's exception handling wraps BIP-85 failures in SeedPassError,
|
||||
which is fine -- but an entropy failure must never be reachable by any
|
||||
handler that could substitute a value. Keeping the draw outside the try is
|
||||
the structural version of that guarantee, stronger than narrowing which
|
||||
exception types get caught.
|
||||
"""
|
||||
from seedpass.core import manager as manager_module
|
||||
|
||||
sentinel = OSError("entropy pool unavailable")
|
||||
|
||||
def _explode(_n):
|
||||
raise sentinel
|
||||
|
||||
monkeypatch.setattr(manager_module.os, "urandom", _explode)
|
||||
|
||||
with pytest.raises(OSError) as excinfo:
|
||||
manager_module.PasswordManager.generate_bip85_seed(object())
|
||||
|
||||
# Propagates as itself, not repackaged -- proof nothing caught it.
|
||||
assert excinfo.value is sentinel
|
||||
|
||||
|
||||
@pytest.mark.parametrize("words_num,expected", [(12, 12), (24, 24)])
|
||||
def test_master_seed_word_count_is_selectable(words_num, expected):
|
||||
"""L2: the master seed can now be 256-bit, not only 128-bit."""
|
||||
from seedpass.core.manager import PasswordManager
|
||||
|
||||
mnemonic = PasswordManager.generate_bip85_seed(object(), words_num=words_num)
|
||||
assert len(mnemonic.split()) == expected
|
||||
|
||||
|
||||
def test_master_seed_default_is_unchanged():
|
||||
"""Existing profiles are 12-word; the default must not move under them."""
|
||||
from seedpass.core.manager import PasswordManager
|
||||
|
||||
assert len(PasswordManager.generate_bip85_seed(object()).split()) == 12
|
||||
|
||||
|
||||
def test_unsupported_word_count_is_rejected():
|
||||
from seedpass.core.errors import SeedPassError
|
||||
from seedpass.core.manager import PasswordManager
|
||||
|
||||
for bad in (0, 11, 18, 25, -12):
|
||||
with pytest.raises(SeedPassError, match="Seed word count"):
|
||||
PasswordManager.generate_bip85_seed(object(), words_num=bad)
|
||||
|
||||
|
||||
def test_all_zero_entropy_is_not_currently_detected(monkeypatch):
|
||||
"""Recorded gap, not an endorsement.
|
||||
|
||||
|
||||
Reference in new issue
Block a user