Support GnuPG AEAD password entries
This commit is contained in:
@@ -38,6 +38,8 @@ encryption-capable primary key. Output uses AES-256 in a version 1
|
||||
symmetrically-encrypted integrity-protected data packet and deliberately does
|
||||
not add a compression packet, matching upstream `pass --compress-algo=none`.
|
||||
Every resolved recipient receives a public-key encrypted session-key packet.
|
||||
IronStorage continues to produce this packet-type-18 SEIPDv1/MDC profile so
|
||||
existing output remains unchanged.
|
||||
|
||||
Decryption first examines those recipient packets. A secret is requested only
|
||||
for imported protected keys that can match the message; unavailable identities
|
||||
@@ -45,6 +47,37 @@ are skipped so any one recipient of a multi-recipient entry can decrypt it.
|
||||
Cancellation stops immediately. Wrong secrets, malformed messages, and a lack
|
||||
of matching secret keys remain distinct failures.
|
||||
|
||||
For compatibility with password stores written by modern GnuPG, decryption
|
||||
also accepts GnuPG's packet-type-20 OCB AEAD extension; the checked-in
|
||||
GnuPG 2.4.8 compatibility case uses AES-256.
|
||||
This is an explicit read-compatibility profile: it does not enable historical
|
||||
unauthenticated encrypted-data packets, accept unsupported packet-20 modes, or
|
||||
change the format IronStorage writes. AEAD authentication must succeed before
|
||||
the provider is told that an interactively supplied passphrase was accepted;
|
||||
wrong passphrases and tampered ciphertext therefore cannot be persisted.
|
||||
|
||||
### Upstream `pass` format boundary
|
||||
|
||||
The format boundary was re-audited against the current upstream tools on
|
||||
2026-08-10. [`pass` 1.7.4 delegates reads and writes directly to
|
||||
GnuPG](https://git.zx2c4.com/password-store/plain/src/password-store.sh): reads
|
||||
use `gpg -d`, while writes use `gpg -e` with `--compress-algo=none`; `pass`
|
||||
does not select or parse an encrypted-data packet itself. The current
|
||||
[Homebrew `pass` formula](https://formulae.brew.sh/formula/pass) packages that
|
||||
same release with GnuPG 2.5.21. GnuPG's
|
||||
[OpenPGP options](https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html)
|
||||
state that public-key encryption selects CFB+MDC or OCB from recipient key
|
||||
preferences, which explains why an ordinary current `pass` installation can
|
||||
write packet type 20 without a `pass` option requesting it.
|
||||
|
||||
Default `pass` does not opt into unauthenticated legacy decryption. GnuPG made
|
||||
missing-MDC messages a hard failure in 2.2.8 and requires the explicit,
|
||||
dangerous `--ignore-mdc-error` override to recover plaintext from them. The
|
||||
[GnuPG 2.2.8 security release](https://lists.gnupg.org/pipermail/gnupg-users/2018-June/060644.html)
|
||||
warns against using that override unconditionally. IronStorage therefore keeps
|
||||
legacy packet-type-9 decryption disabled: its default behavior matches default
|
||||
`pass` while preserving the authenticated-decryption guarantee.
|
||||
|
||||
## Secret lifetime and recipient signatures
|
||||
|
||||
Decrypted data and provider-returned unlock secrets use `SecretBytes`. Its
|
||||
@@ -65,12 +98,15 @@ from another imported key is rejected.
|
||||
## Compatibility evidence
|
||||
|
||||
`crates/storage/tests/fixtures/compatibility` contains protected public and
|
||||
secret exports, single- and multi-recipient `.gpg` entries, and signed
|
||||
recipient files. The fixture audit established that GnuPG decrypts the packet
|
||||
profile used by the generator. Production tests then exercise that same
|
||||
uncompressed `MessageBuilder` profile through `KeyStore::encrypt`, independently
|
||||
parse and decrypt its output, decrypt every checked-in GnuPG-audited entry, and
|
||||
verify both checked-in and newly generated recipient signatures.
|
||||
secret exports, single- and multi-recipient `.gpg` entries, signed recipient
|
||||
files, and a GnuPG 2.4.8-produced packet-type-20 AES-256/OCB entry. The fixture
|
||||
audit established that GnuPG decrypts the packet profile used by the generator.
|
||||
Production tests then exercise that same uncompressed `MessageBuilder` profile
|
||||
through `KeyStore::encrypt`, independently parse and decrypt its output, decrypt
|
||||
every checked-in GnuPG-audited entry through the storage API, and verify both
|
||||
checked-in and newly generated recipient signatures. Packet-type-20 tests also
|
||||
cover the exact encryption subkey, wrong passphrases, authentication failure,
|
||||
missing secret keys, unsupported modes, and deferred secret persistence.
|
||||
|
||||
Tests never use a real user keyring and application runtime never executes an
|
||||
external cryptographic tool.
|
||||
|
||||
Reference in New Issue
Block a user