Skip to content

AEAD architecture: FAuthObj + multi-call GCM (from PR #90 concern A)#102

Open
omonien wants to merge 1 commit into
MHumm:developmentfrom
omonien:package/aead-architecture
Open

AEAD architecture: FAuthObj + multi-call GCM (from PR #90 concern A)#102
omonien wants to merge 1 commit into
MHumm:developmentfrom
omonien:package/aead-architecture

Conversation

@omonien

@omonien omonien commented Jul 26, 2026

Copy link
Copy Markdown

For Markus — AEAD architecture (no ChaCha)

This is package A only: a careful architecture / GCM fix extracted from donor PR #90.
ChaCha / XChaCha / Poly1305 / AES-NI are not in this PR. Those stay separate packages on the fork for later.

Why bother (simple words)

Today, authenticated modes (especially GCM) are a bit of a special case:

  • GCM and CCM each have their own fields and switch statements.
  • GCM did not correctly support encrypting/decrypting a message in several chunks (streaming). Tags could look fine for one-shot use and still be wrong for multi-call use.
  • That is a real correctness problem for anyone who streams AES-GCM (network buffers, files, etc.).

This PR does three practical things:

  1. One place for “authenticated mode” work — a single FAuthObj instead of dual FGCM / FCCM wiring.
  2. Correct multi-call GCM — partial blocks and keystream are carried across Encode/Decode calls; the tag is finalized in Done.
  3. A clear lifecycle everyone can follow:
    Init → (AAD / tag length) → Encode/Decode* → Done → read / check tag.

Benefits for existing code (already, without ChaCha)

You get value even if we never merge ChaCha:

Benefit Why it matters now
Correct AES-GCM streaming Multi-chunk encrypt/decrypt produces the same ciphertext and tag as one-shot
Safer “after Done” behaviour Further Encode/Decode after finalize raises until the next Init
Simpler mode wiring Less case FMode of duplication for auth properties / Done
Solid foundation for future AEAD New modes can plug in as another FAuthObj implementation without rewriting GCM again
Public API kept IDECAuthenticatedCipher names stay; protected EncodeGCM / DecodeGCM kept as wrappers

Call site note: for multi-call GCM, call Done before reading CalculatedAuthenticationResult. Paths that already call Done (most of the suite / normal demo style) keep working. Single-shot “encode then Done then tag” remains the normal pattern.

CCM stays one-shot as before (no fake multi-chunk for CCM).

Relation to the donor PR (#90)

PR #90 mixed architecture, GCM rewrite, ChaCha, Poly1305, SIMD, AES-NI, … in one large change.

For this package we:

  • Cut out only the AEAD architecture + GCM multi-call concern
  • Reworked thoroughly — did not take the donor’s GCM streaming model as-is (it treated a partial call as end-of-message and broke unaligned multi-chunk streams)
  • Kept the good idea (shared auth object + deferred finalize) and replaced the weak streaming engine with a correct multi-call design (same spirit as the GCM multi-chunk work discussed in the cleanup / Option A direction)
  • Left ChaCha / Poly1305 / CPU / AES-NI for later packages so this review stays focused

So: donor as inspiration and reference, not a bulk merge.

What changed (files)

File Role
Source/DECAuthenticatedCipherModesBase.pas Shared base + virtual Done
Source/DECCipherModes.pas FAuthObj wiring, leak-safe InitMode, unified finalize + ExpectedTag check
Source/DECCipherModesGCM.pas Multi-call GCM (GHASH partial + CTR keystream remainder + FFinalized)
Unit Tests/Tests/TestDECCipherModesGCM.pas Multi-chunk + Done lifecycle tests
Unit Tests/Data/gcmEncryptExtIV256_large.rsp Corrected large-vector tag (CT already matched AES-GCM)
Docs/plans/2026-07-25-aead-architecture.md Design decisions (fork planning note)

Tests (emphasis)

Thorough coverage was a hard requirement for this package — architecture without a green GCM/CCM signal is not mergeable.

Verified locally (Delphi 13, Win32 Console DUnit):

  • GCM suite: 19/19 including:
    • existing CAVS / stream / auth-failure cases
    • multi-chunk two equal blocks (16+16)
    • uneven multi-chunk (7+25) for GHASH + keystream partials
    • multi-chunk decode with expected-tag verify
    • Done idempotent
    • Encode/Decode after Done rejected until re-Init
  • CCM suite: 16/16 (one-shot regression under the new wiring)
  • Non-AEAD cipher modes: green (no accidental coupling)
  • Full suite residual reds at the time of work: pre-existing Keccak vectors only (separate PRs) — no new reds from this package

Risk

Medium — touches core GCM authentication. Mitigations: multi-chunk NIST-style vectors, Done lifecycle tests, CCM full regression, no public interface rename.

Out of scope (intentionally)

Suggested review order

  1. Lifecycle: Init → multi Encode/DecodeDone → tag
  2. GCM state: GHASH partial, keystream remainder, FFinalized
  3. FAuthObj + property / Done wiring in DECCipherModes.pas
  4. New tests (multi-chunk + post-Done)
  5. CCM still green

Test plan

  • Build library Debug Win32
  • Run full unit test suite (or at least GCM + CCM)
  • Spot-check: multi-chunk GCM + Done after last chunk before reading tag

Happy to adjust wording or split further if anything feels too large.

…m#99)

Extract Concern A from the ChaCha PR MHumm#90 donor without ChaCha/Poly1305.

- Polymorphic FAuthObj replaces dual FGCM/FCCM fields; public IDECAuthenticatedCipher unchanged
- Keep EncodeGCM/DecodeGCM/EncodeCCM/DecodeCCM as protected wrappers (no rename break)
- GCM multi-call: absorb PR MHumm#99 streaming (GHASH partial + CTR keystream remainder + Done/FFinalized)
- Reject PR MHumm#90 fIsLastBlock CTR model (incorrect for unaligned multi-chunk)
- Base Done virtual (no-op for CCM one-shot); TDECCipherModes.Done finalizes then verifies ExpectedTag
- InitMode always FreeAndNil(FAuthObj) before recreate (leak fix)
- Multi-chunk and Done-lifecycle unit tests; corrected large GCM rsp tag

See Docs/plans/2026-07-25-aead-architecture.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant