Modernize packaging, add fast path options#21
Modernize packaging, add fast path options#21mahmoud wants to merge 5 commits intoSimpleLegal:masterfrom
Conversation
- Remove all Python 2 compat (unicode shims, cStringIO, imp, __future__) - Add per-custodian KDF parameter storage (v1 pwdkm format) - v0 custodians (existing) continue using module-level OPSLIMIT/MEMLIMIT - v1 custodians store opslimit/memlimit in their pwdkm field - Backward compatible: v0 files load and work unchanged - Add KDF_SENSITIVE and KDF_INTERACTIVE named parameter tuples - SENSITIVE: ~0.8s per KDF call (production default) - INTERACTIVE: ~0.1s per KDF call (dev/testing, 8x faster) - Add --fast-crypto CLI flag for init/add-key-custodian - Convert setup.py to pyproject.toml - Modernize tox.ini (py39-py313) - Expand test suite: 11 tests (was 4), covering v0/v1 round-trip, coexistence, KDF params, check_creds, audit log, error cases - Bump version to 24.0.0dev
- KeyFile.migrate_owner: batch add owner across all domains - KeyFile.get_custodian_domains: list domains a custodian owns - set_key_custodian_passphrase: accept opslimit/memlimit params - CLI: migrate-owner subcommand with confirmation prompt - CLI: list-user-secrets subcommand (read-only) - CLI: set-key-custodian-passphrase now supports --fast-crypto flag - Tests for all new functionality
Raw-key custodians bypass argon2 entirely. The passphrase IS the entropy (256 bits), so password stretching adds only latency. Format: P<64 lowercase hex chars>P (e.g. P0a1b2c...P) - v2 pwdkm format: version(1=0x02) + salt(8) + pubkey(32) - _kdf_raw: sha512(passphrase + salt + name)[:32], no argon2 - generate_raw_passphrase(): creates P<64hex>P from os.urandom(32) - is_raw_passphrase(): validates format - KeyFile.add_raw_key_custodian(): creates v2 custodian - CLI: add-raw-key-custodian subcommand - Generates key, displays once with stern warning - Requires typing YES to confirm key was saved - Aborts cleanly on decline - v0/v1/v2 custodians coexist in same protected.yaml - 22 tests (6 new)
Breaking change: --fast-crypto flag removed in favor of --key-type. pprotect add-key-custodian --key-type fast # was --fast-crypto pprotect add-key-custodian --key-type raw # was add-raw-key-custodian pprotect add-key-custodian # default: hard (unchanged) New: rekey-custodian command Changes an existing custodian's key type and passphrase in one step. Re-encrypts all domain ownership keys automatically. pprotect rekey-custodian --key-type fast # move existing custodian to fast KDF pprotect rekey-custodian --key-type raw # move to raw key (generates P<hex>P) Internal: KeyFile._replace_key_custodian extracted from set_key_custodian_passphrase for reuse by rekey_custodian. 23 tests pass.
|
cc @kurtbrose |
|
oh nice, you added raw key as well, so there are three modes :-) yea, in practice the way I've used it locally and in prod is that there's a high entropy machine generated key anyway, so we could just skip the KDF entirely actually with no loss in functionality I'll give it a deeper look soon, but at first glance looks pretty good |
| def _kdf_raw(creds, salt): | ||
| '''Derive key directly from high-entropy passphrase (P<64hex>P format). | ||
| No argon2 — the passphrase IS the entropy.''' | ||
| name = creds.name.encode('utf8') | ||
| passphrase = creds.passphrase.encode('utf8') | ||
| return hashlib.sha512(passphrase + salt + name).digest()[:nacl.public.PrivateKey.SIZE] |
There was a problem hiding this comment.
no need for hashlib, it should already be 32 bytes, just check that len(passphrase) == PrivateKey.SIZE (which I believe is 32 bytes) and send it on through
|
|
||
| def generate_raw_passphrase(): | ||
| '''Generate a P<64hex>P raw-key passphrase with 256 bits of entropy.''' | ||
| return 'P' + os.urandom(32).hex() + 'P' |
There was a problem hiding this comment.
if you don't care about pre-3.6 compatibility, secrets.key_hex() is basically a "stlib approved" way to call os.urandom().hex() -- it's literally the same API, just exposed through a different interface
(I learned this the other week)
kurtbrose
left a comment
There was a problem hiding this comment.
nice -- a lot of modernization; also I like the idea of baking in the "high entropy passphrase" to the data, that makes sense
small suggestion is just, skip the hmac; high entropy with size = size, you are done
Still using pocket protector in production. Ran into an issue where I wanted to speed up application startup and pprotect's KDF functionality was slowing me down. Added two options for fast paths: "raw" where there's no KDF (just a huge passphrase) and "fast" where the KDF isn't quite as hard. "hard" is still the default and I tested that all formats still work. Also test coverage is up to 98% (from 95%).