Review

Passphrase auth for QuietHarbor estate vaults

QuietHarbor stores advance directives and digital wills for families who refuse short passwords. Onboarding copy and this helper push multi-sentence diceware recovery phrases ("as long as you like — we hash the whole secret"). Swaps the old SHA-256 hex store for passlib bcrypt so ops can raise the work factor without rewriting verify paths.

passlibTier 4securitybcryptpasslibauth

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

services/vault/passphrases.py+15-7
11from __future__ import annotations
22
3-import hashlib
3+from passlib.context import CryptContext
44
5-# legacy: single SHA-256 hex — no salt, no work factor
6-def hash_passphrase(passphrase: str) -> str:
7- return hashlib.sha256(passphrase.encode("utf-8")).hexdigest()
8-
9-def verify_passphrase(passphrase: str, stored: str) -> bool:
10- return hash_passphrase(passphrase) == stored
5+# bcrypt: adaptive cost; passphrases may be arbitrarily long (diceware / full sentences).
6+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto", bcrypt__rounds=12)
7+
8+MIN_PASSPHRASE_CHARS = 24 # onboarding encourages 8+ diceware words
9+
10+def hash_passphrase(passphrase: str) -> str:
11+ secret = passphrase.strip()
12+ if len(secret) < MIN_PASSPHRASE_CHARS:
13+ raise ValueError("passphrase too short for QuietHarbor vaults")
14+ # Entire UTF-8 secret is one-way hashed; length is not truncated.
15+ return pwd_context.hash(secret)
16+
17+def verify_passphrase(passphrase: str, stored: str) -> bool:
18+ return pwd_context.verify(passphrase.strip(), stored)