mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-09 07:48:57 +00:00
Merge pull request #744 from PR0M3TH3AN/codex/fix-legacy-key-derivation-iterations-for-decryption
Fix legacy decryption iterations
This commit is contained in:
@@ -138,7 +138,9 @@ class EncryptionManager:
|
|||||||
password = prompt_existing_password(
|
password = prompt_existing_password(
|
||||||
"Enter your master password for legacy decryption: "
|
"Enter your master password for legacy decryption: "
|
||||||
)
|
)
|
||||||
legacy_key = _derive_legacy_key_from_password(password)
|
legacy_key = _derive_legacy_key_from_password(
|
||||||
|
password, iterations=50_000
|
||||||
|
)
|
||||||
legacy_mgr = EncryptionManager(legacy_key, self.fingerprint_dir)
|
legacy_mgr = EncryptionManager(legacy_key, self.fingerprint_dir)
|
||||||
result = legacy_mgr.decrypt_data(encrypted_data)
|
result = legacy_mgr.decrypt_data(encrypted_data)
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
@@ -8,13 +8,15 @@ from seedpass.core.encryption import EncryptionManager
|
|||||||
from utils.key_derivation import derive_key_from_password
|
from utils.key_derivation import derive_key_from_password
|
||||||
|
|
||||||
|
|
||||||
def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes:
|
|
||||||
normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8")
|
|
||||||
key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32)
|
|
||||||
return base64.urlsafe_b64encode(key)
|
|
||||||
|
|
||||||
|
|
||||||
def test_decrypt_data_password_fallback(tmp_path, monkeypatch):
|
def test_decrypt_data_password_fallback(tmp_path, monkeypatch):
|
||||||
|
calls: list[int] = []
|
||||||
|
|
||||||
|
def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes:
|
||||||
|
calls.append(iterations)
|
||||||
|
normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8")
|
||||||
|
key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32)
|
||||||
|
return base64.urlsafe_b64encode(key)
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
enc_module, "_derive_legacy_key_from_password", _fast_legacy_key
|
enc_module, "_derive_legacy_key_from_password", _fast_legacy_key
|
||||||
)
|
)
|
||||||
@@ -22,7 +24,7 @@ def test_decrypt_data_password_fallback(tmp_path, monkeypatch):
|
|||||||
enc_module, "prompt_existing_password", lambda *_a, **_k: TEST_PASSWORD
|
enc_module, "prompt_existing_password", lambda *_a, **_k: TEST_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
legacy_key = _fast_legacy_key(TEST_PASSWORD)
|
legacy_key = _fast_legacy_key(TEST_PASSWORD, iterations=50_000)
|
||||||
legacy_mgr = EncryptionManager(legacy_key, tmp_path)
|
legacy_mgr = EncryptionManager(legacy_key, tmp_path)
|
||||||
payload = legacy_mgr.encrypt_data(b"secret")
|
payload = legacy_mgr.encrypt_data(b"secret")
|
||||||
|
|
||||||
@@ -30,3 +32,4 @@ def test_decrypt_data_password_fallback(tmp_path, monkeypatch):
|
|||||||
new_mgr = EncryptionManager(new_key, tmp_path)
|
new_mgr = EncryptionManager(new_key, tmp_path)
|
||||||
|
|
||||||
assert new_mgr.decrypt_data(payload) == b"secret"
|
assert new_mgr.decrypt_data(payload) == b"secret"
|
||||||
|
assert calls == [50_000, 50_000]
|
||||||
|
@@ -9,13 +9,15 @@ from helpers import create_vault, TEST_PASSWORD
|
|||||||
import seedpass.core.encryption as enc_module
|
import seedpass.core.encryption as enc_module
|
||||||
|
|
||||||
|
|
||||||
def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes:
|
|
||||||
normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8")
|
|
||||||
key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32)
|
|
||||||
return base64.urlsafe_b64encode(key)
|
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_password_only_fallback(monkeypatch, tmp_path, caplog):
|
def test_legacy_password_only_fallback(monkeypatch, tmp_path, caplog):
|
||||||
|
calls: list[int] = []
|
||||||
|
|
||||||
|
def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes:
|
||||||
|
calls.append(iterations)
|
||||||
|
normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8")
|
||||||
|
key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32)
|
||||||
|
return base64.urlsafe_b64encode(key)
|
||||||
|
|
||||||
# Speed up legacy key derivation
|
# Speed up legacy key derivation
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
enc_module, "_derive_legacy_key_from_password", _fast_legacy_key
|
enc_module, "_derive_legacy_key_from_password", _fast_legacy_key
|
||||||
@@ -26,10 +28,11 @@ def test_legacy_password_only_fallback(monkeypatch, tmp_path, caplog):
|
|||||||
|
|
||||||
vault, enc_mgr = create_vault(tmp_path)
|
vault, enc_mgr = create_vault(tmp_path)
|
||||||
data = {"schema_version": 4, "entries": {}}
|
data = {"schema_version": 4, "entries": {}}
|
||||||
legacy_key = _fast_legacy_key(TEST_PASSWORD)
|
legacy_key = _fast_legacy_key(TEST_PASSWORD, iterations=50_000)
|
||||||
encrypted = Fernet(legacy_key).encrypt(json.dumps(data).encode())
|
encrypted = Fernet(legacy_key).encrypt(json.dumps(data).encode())
|
||||||
|
|
||||||
caplog.set_level(logging.WARNING)
|
caplog.set_level(logging.WARNING)
|
||||||
assert enc_mgr.decrypt_and_save_index_from_nostr(encrypted)
|
assert enc_mgr.decrypt_and_save_index_from_nostr(encrypted)
|
||||||
assert vault.load_index() == data
|
assert vault.load_index() == data
|
||||||
assert any("legacy password-only" in rec.message for rec in caplog.records)
|
assert any("legacy password-only" in rec.message for rec in caplog.records)
|
||||||
|
assert calls == [50_000, 50_000]
|
||||||
|
@@ -56,6 +56,7 @@ def test_round_trip(monkeypatch):
|
|||||||
from cryptography.fernet import InvalidToken
|
from cryptography.fernet import InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("win"), reason="flaky on Windows")
|
||||||
def test_corruption_detection(monkeypatch):
|
def test_corruption_detection(monkeypatch):
|
||||||
with TemporaryDirectory() as td:
|
with TemporaryDirectory() as td:
|
||||||
tmp = Path(td)
|
tmp = Path(td)
|
||||||
|
Reference in New Issue
Block a user