Decrypt GnuPG AEAD packet type 20 password-store entries #61

Closed
opened 2026-08-10 08:12:50 +00:00 by hugo · 1 comment
Owner

Objective

Support existing upstream-compatible password stores whose GPG entries use the GnuPG AEAD packet type 20 format.

Root cause

The affected entries correctly target encryption subkey 4D463BF6BA4D8A9C under primary key 3B98…5429, so key selection is not the failure. The real store's 547 entries use AES-256/OCB GnuPG AEAD packets (tag 20), while IronStorage's current compatibility fixtures and documented profile cover only SEIPD/MDC packet type 18. pgp 0.20 requires GnuPG AEAD support to be explicitly enabled, but crates/storage/src/crypto.rs currently uses default Message::decrypt behavior and rejects tag 20. The resulting decrypt error also causes a correctly prompted passphrase to be discarded rather than persisted.

Scope

  • Enable GnuPG AEAD decryption through crates/storage without weakening existing packet validation.
  • Add a checked-in type-20 compatibility fixture produced in the upstream password-store format, including its public/protected secret key material.
  • Prove the fixture decrypts with the matching encryption subkey and correct passphrase.
  • Preserve typed failures for wrong passphrases, corrupt AEAD data, missing keys, and unsupported packet modes.
  • Update cryptography compatibility documentation to describe both accepted formats.
  • Do not rewrite or re-encrypt existing password stores as a workaround.

Acceptance criteria

  • A real packet-tag-20 AES-256/OCB fixture decrypts through the normal crates/storage entry path.
  • Existing packet-tag-18/MDC fixtures and encryption behavior remain compatible.
  • Tampering and wrong-passphrase tests fail safely without persisting rejected credentials.
  • No CLI or application layer parses OpenPGP packets or owns this compatibility rule.
  • All repository gates pass.
## Objective Support existing upstream-compatible password stores whose GPG entries use the GnuPG AEAD packet type 20 format. ## Root cause The affected entries correctly target encryption subkey 4D463BF6BA4D8A9C under primary key 3B98…5429, so key selection is not the failure. The real store's 547 entries use AES-256/OCB GnuPG AEAD packets (tag 20), while IronStorage's current compatibility fixtures and documented profile cover only SEIPD/MDC packet type 18. pgp 0.20 requires GnuPG AEAD support to be explicitly enabled, but crates/storage/src/crypto.rs currently uses default Message::decrypt behavior and rejects tag 20. The resulting decrypt error also causes a correctly prompted passphrase to be discarded rather than persisted. ## Scope - Enable GnuPG AEAD decryption through crates/storage without weakening existing packet validation. - Add a checked-in type-20 compatibility fixture produced in the upstream password-store format, including its public/protected secret key material. - Prove the fixture decrypts with the matching encryption subkey and correct passphrase. - Preserve typed failures for wrong passphrases, corrupt AEAD data, missing keys, and unsupported packet modes. - Update cryptography compatibility documentation to describe both accepted formats. - Do not rewrite or re-encrypt existing password stores as a workaround. ## Acceptance criteria - A real packet-tag-20 AES-256/OCB fixture decrypts through the normal crates/storage entry path. - Existing packet-tag-18/MDC fixtures and encryption behavior remain compatible. - Tampering and wrong-passphrase tests fail safely without persisting rejected credentials. - No CLI or application layer parses OpenPGP packets or owns this compatibility rule. - All repository gates pass.
hugo added this to the 02 - Mutt-style terminal UI milestone 2026-08-10 08:12:50 +00:00
hugo added the bug label 2026-08-10 08:12:50 +00:00
Author
Owner

Implemented in commit 977eb23 and pushed to main.

Storage now opts into pgp 0.20 GnuPG AEAD decryption through DecryptionOptions while keeping legacy unauthenticated packets disabled and preserving IronStorage encryption as packet type 18 SEIPDv1/MDC.

Compatibility evidence:

  • Added a genuine GnuPG 2.4.8-produced packet type 20 AES-256/OCB password-store fixture addressed to the synthetic Alice encryption subkey, with a protected secret key, expected plaintext, producer profile, and SHA-256 provenance.
  • Decrypted it through Repository and VaultReader, not a test-only packet shortcut.
  • Verified exact encryption-subkey matching, correct passphrase acceptance, wrong-passphrase rejection, corrupt AEAD authentication failure, missing-key handling, unsupported AEAD-mode rejection, and no persistence of rejected prompted passphrases.
  • Added an explicit regression assertion that IronStorage output remains packet type 18 SEIPDv1.

The upstream audit was also documented: pass 1.7.4 delegates gpg file reads/writes to GnuPG; current Homebrew pass depends on GnuPG 2.5.21; GnuPG chooses CFB+MDC or packet-20 OCB from recipient preferences. Default GnuPG rejects missing-MDC legacy data, so IronStorage keeps that unsafe mode disabled.

Verification passed:

  • cargo fmt --all -- --check
  • RUSTFLAGS=-D warnings cargo check --workspace --all-targets
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
Implemented in commit 977eb23 and pushed to main. Storage now opts into pgp 0.20 GnuPG AEAD decryption through DecryptionOptions while keeping legacy unauthenticated packets disabled and preserving IronStorage encryption as packet type 18 SEIPDv1/MDC. Compatibility evidence: - Added a genuine GnuPG 2.4.8-produced packet type 20 AES-256/OCB password-store fixture addressed to the synthetic Alice encryption subkey, with a protected secret key, expected plaintext, producer profile, and SHA-256 provenance. - Decrypted it through Repository and VaultReader, not a test-only packet shortcut. - Verified exact encryption-subkey matching, correct passphrase acceptance, wrong-passphrase rejection, corrupt AEAD authentication failure, missing-key handling, unsupported AEAD-mode rejection, and no persistence of rejected prompted passphrases. - Added an explicit regression assertion that IronStorage output remains packet type 18 SEIPDv1. The upstream audit was also documented: pass 1.7.4 delegates gpg file reads/writes to GnuPG; current Homebrew pass depends on GnuPG 2.5.21; GnuPG chooses CFB+MDC or packet-20 OCB from recipient preferences. Default GnuPG rejects missing-MDC legacy data, so IronStorage keeps that unsafe mode disabled. Verification passed: - cargo fmt --all -- --check - RUSTFLAGS=-D warnings cargo check --workspace --all-targets - cargo clippy --workspace --all-targets -- -D warnings - cargo test --workspace
hugo closed this issue 2026-08-10 08:58:39 +00:00
Sign in to join this conversation.