ADR-0032: Standard 12-Byte Nonce Size for AES-GCM
- Status: accepted
- Date: 2024-11-27
- Tags: Security, Cryptography, AES-GCM
Context and Problem Statement
SPIKE uses AES-GCM for symmetric encryption in several places:
- Cipher API (encryption as a service)
- Bootstrap verification
- Backend storage encryption
GCM technically supports multiple nonce sizes via Go’s cipher.NewGCMWithNonceSize(),
but the standard 12-byte (96-bit) nonce is recommended by NIST. Should SPIKE
support configurable nonce sizes, or hardcode the standard 12-byte size?
Decision Drivers
- Security: Follow NIST recommendations and avoid non-standard configurations
- Performance: 12-byte nonces use a more efficient internal counter mode
- Interoperability: Clients need to know the expected nonce size
- Simplicity: Avoid unnecessary configuration complexity
Considered Options
- Hardcode 12-byte nonce size - Use the NIST-recommended standard
- Make nonce size configurable - Allow runtime or compile-time configuration
- Use cipher.NonceSize() everywhere - Query the cipher for its nonce size
Decision
Hardcode the 12-byte nonce size as a constant (crypto.GCMNonceSize) and use it
for all nonce validation. Nonce generation already correctly uses c.NonceSize()
from the cipher instance.
Rationale
Why 12 bytes is the right choice
Per NIST SP 800-38D (Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode):
- 96-bit (12-byte) nonces use the efficient counter mode directly
- Other sizes require an additional GHASH operation, adding overhead
- 12 bytes provides sufficient uniqueness for random nonce generation
- This is the default for Go’s
cipher.NewGCM()
Why not make it configurable
- No legitimate use case for non-standard sizes in SPIKE’s context
- Configuration adds complexity and potential for misconfiguration
- Non-standard sizes have security implications that users may not understand
- Protocol versioning (
spikeCipherVersion) exists if changes are ever needed
Consistency in generation vs validation
- Generation: Uses
c.NonceSize()- correct, as the cipher knows its size - Validation: Uses hardcoded constant - correct, as we enforce the standard
This is not inconsistent. Generation queries the cipher (which returns 12 for standard GCM), while validation enforces that incoming data matches our expected standard.
Consequences
Positive
- Follows NIST recommendations
- No configuration complexity
- Consistent behavior across all SPIKE components
- Clear documentation via the constant and this ADR
Negative
- Cannot use non-standard nonce sizes (this is intentional)
- If Go’s default ever changed (extremely unlikely), we would need updates
Implementation Notes
The constant is defined in internal/crypto/gcm.go:
const GCMNonceSize = 12
This is used by:
app/nexus/internal/route/cipher/- Cipher API validationapp/nexus/internal/route/bootstrap/- Bootstrap verification
If a future protocol version requires different nonce handling, increment
spikeCipherVersion and handle accordingly.
- ADR-0032: Standard 12-Byte Nonce Size for AES-GCM
- ADR-0031: AST-Based Test Enforcement for Route Guard Functions
- ADR-0030: Minimal Error Messages in API Responses
- ADR-0029: Restrict Recovery and Restoration Operations to SPIKE Pilot
- ADR-0028: Use Human-Readable Error Messages in CLI Tools
- ADR-0027: Separate Audit Logs from Operational Logs
- ADR-0026: Configurable Data Directory for SPIKE Components
- ADR-0025: Path Patterns as Key Namespaces with Regular Expression Matching
- ADR-0024: Transition from In-Memory Cache to Direct Backend Storage for High Availability
- ADR-0023: Decision Against Implementing Lock/Unlock Mechanism in SPIKE Nexus
- ADR-0022: Continuous Polling of SPIKE Keepers Despite 404 Response
- ADR-0021: SPIKE Keeper as a Stateless Shard Holder
- ADR-0020: Switch to Zola for Documentation System
- ADR-0019: Plugin-Based Storage Backend Architecture
- ADR-0018: Administrative Access to SPIKE
- ADR-0017: Synchronous Persistence for SPIKE Secrets Store
- ADR-0016: Memory-First Secrets Store
- ADR-0015: Use Singular Form for File and Package Naming
- ADR-0014: Maintaining SQLite as SPIKE’s Primary Storage Backend
- ADR-0013: S3-Compatible Storage as SPIKE’s Backing Store
- ADR-0012: HTTP Methods for SPIKE API
- ADR-0011: PostgreSQL as SPIKE’s Backing Store
- ADR-0010: Session Token Storage Strategy for SPIKE Nexus
- ADR-0009: Multi-Administrator Support System
- ADR-0008: Administrative Access Control System
- ADR-0007: Root Key Lifecycle and Management Strategy
- ADR-0006: Trust Boundary Definition and Security Assumptions
- ADR-0005: Use SPIFFE mTLS for Inter-Component Authentication and Communication
- ADR-0004: SPIKE Keeper Minimalist Design Approach
- ADR-0003: Root Key Management and Storage Strategy
- ADR-0002: Use Docsify for Documentation System
- ADR-0001: Display Secrets in Plain Text in SPIKE Pilot Admin CLI