Skip to content

Latest commit

 

History

History
67 lines (52 loc) · 2.45 KB

design.md

File metadata and controls

67 lines (52 loc) · 2.45 KB

Encryption envelope design

Status: accepted for the initial v0.1.0 implementation Date: 2026-09-22

Decision

The initial public module exposes authenticated encryption for complete byte slices through a root encryption package. It does not publish or retain the old AES-CBC API, legacy ciphertext decoding, padding helpers, or a streaming facade.

The module uses AES-256-GCM through Go's cipher.NewGCMWithRandomNonce. A Box accepts one 32-byte random key, generates a new 96-bit nonce for every message, and stores the nonce and authentication tag in a versioned envelope.

Public API

key := encryption.GenerateKey()
box, err := encryption.New(key)
envelope := box.Seal(plaintext, additionalData)
plaintext, err = box.Open(envelope, additionalData)

Key persistence, distribution, rotation, passphrase derivation, KMS integration, and durable storage are application responsibilities.

Version 1 envelope

offset  size  field
0       4     magic: "QBEN"
4       1     format version: 0x01
5       1     algorithm: 0x01 (AES-256-GCM with random nonce)
6       12    random GCM nonce
18      n     ciphertext
18+n    16    GCM authentication tag

The six-byte header and caller-supplied additional data are authenticated as AEAD additional data. Additional data is not stored in the envelope and must be supplied byte-for-byte to Open.

All parse, compatibility, and authentication failures return one public ErrInvalidEnvelope value and no plaintext. Unknown versions or algorithms fail closed.

Security bounds

  • Keys contain exactly 32 random bytes; passwords are not accepted as keys.
  • A key must not seal more than 2^32 messages because random GCM nonces have a collision bound.
  • The module does not provide streaming. A future streaming format would need independent nonce, ordering, truncation, and replay rules.
  • The module does not attempt in-memory key zeroization, rollback protection, replay protection, or key lifecycle management.

Rejected alternatives

  • AES-CBC was rejected because the imported implementation was unauthenticated, deterministic under IV reuse, padding-ambiguous, and not a correct stream.
  • Caller-managed nonces were rejected because nonce reuse is a severe and unnecessary API footgun for the intended use.
  • Algorithm selection in the public API was rejected for v0.1.0; the envelope identifier reserves explicit future format evolution without making cryptographic choice a caller responsibility.