Replace instanceof chain in CryptoAlgorithms.create() with a Java 21 pattern switch #20

Open
opened 2026-03-27 00:37:32 +01:00 by galambos · 0 comments
Owner

The AUDIT_MODE == WRAP branch in CryptoAlgorithms.create() dispatches over
five known CryptoContext subtypes using a chain of instanceof checks, each
followed by an identical AuditedContexts.wrap(ctx, listener, role) call and a
@SuppressWarnings("unchecked") cast. Adding a new context type (e.g. an
agreement context, a KDF context) requires a manual edit to this chain; forgetting
to do so silently falls through to the unwrapped return ctx at the bottom.

Why this matters

The current structure scales poorly as new context types are added and provides no
compile-time safety net. Java 21 sealed interfaces combined with pattern-matching
switch allow the compiler to enforce exhaustiveness — a missing case becomes a
compile error rather than a silent audit gap.

Proposed change

  1. Declare CryptoContext (or introduce a WrappableCryptoContext sub-interface)
    as a sealed interface permitting the known concrete subtypes:
    SignatureContext, EncryptionContext, KemContext, DigestContext,
    MacContext.
  2. Replace the instanceof chain with a pattern-matching switch:
return switch (ctx) {
    case SignatureContext  sc -> (C) AuditedContexts.wrap(sc, listener, role);
    case EncryptionContext ec -> (C) AuditedContexts.wrap(ec, listener, role);
    case KemContext       kc -> (C) AuditedContexts.wrap(kc, listener, role);
    case DigestContext    dc -> (C) AuditedContexts.wrap(dc, listener, role);
    case MacContext       mc -> (C) AuditedContexts.wrap(mc, listener, role);
};

With a sealed hierarchy and no default, the compiler will flag any future
subtype that is not explicitly handled, making audit gaps visible at build time.

  1. If sealing CryptoContext is not desirable (e.g. to allow third-party
    extensions), retain default -> ctx and document the fallback explicitly.

Acceptance criteria

  • The instanceof chain is replaced by a switch expression.
  • If CryptoContext is sealed: no default branch; the compiler enforces
    exhaustiveness.
  • If CryptoContext remains open: default -> ctx is present and Javadoc
    documents that unknown types are returned unwrapped.
  • All existing tests pass.
  • @SuppressWarnings("unchecked") casts are confined to the switch arms, not
    repeated in an outer block.
The `AUDIT_MODE == WRAP` branch in `CryptoAlgorithms.create()` dispatches over five known `CryptoContext` subtypes using a chain of `instanceof` checks, each followed by an identical `AuditedContexts.wrap(ctx, listener, role)` call and a `@SuppressWarnings("unchecked")` cast. Adding a new context type (e.g. an agreement context, a KDF context) requires a manual edit to this chain; forgetting to do so silently falls through to the unwrapped `return ctx` at the bottom. ## Why this matters The current structure scales poorly as new context types are added and provides no compile-time safety net. Java 21 sealed interfaces combined with pattern-matching `switch` allow the compiler to enforce exhaustiveness — a missing case becomes a compile error rather than a silent audit gap. ## Proposed change 1. Declare `CryptoContext` (or introduce a `WrappableCryptoContext` sub-interface) as a `sealed interface` permitting the known concrete subtypes: `SignatureContext`, `EncryptionContext`, `KemContext`, `DigestContext`, `MacContext`. 2. Replace the `instanceof` chain with a pattern-matching `switch`: ```java return switch (ctx) { case SignatureContext sc -> (C) AuditedContexts.wrap(sc, listener, role); case EncryptionContext ec -> (C) AuditedContexts.wrap(ec, listener, role); case KemContext kc -> (C) AuditedContexts.wrap(kc, listener, role); case DigestContext dc -> (C) AuditedContexts.wrap(dc, listener, role); case MacContext mc -> (C) AuditedContexts.wrap(mc, listener, role); }; ``` With a sealed hierarchy and no `default`, the compiler will flag any future subtype that is not explicitly handled, making audit gaps visible at build time. 3. If sealing `CryptoContext` is not desirable (e.g. to allow third-party extensions), retain `default -> ctx` and document the fallback explicitly. ## Acceptance criteria - The `instanceof` chain is replaced by a `switch` expression. - If `CryptoContext` is sealed: no `default` branch; the compiler enforces exhaustiveness. - If `CryptoContext` remains open: `default -> ctx` is present and Javadoc documents that unknown types are returned unwrapped. - All existing tests pass. - `@SuppressWarnings("unchecked")` casts are confined to the switch arms, not repeated in an outer block.
galambos added this to the PKI Foundation Hardening and Regulated Operations Roadmap project 2026-03-27 00:45:05 +01:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Egothor/ZeroEcho#20