feat: add AES-CBC support - #29
Conversation
The G+D CII perso request for the card vending machine needs AES-CBC, so the library needs a CBC mode alongside the existing GCM wrapper. CBCCipher is a separate type from Cipher rather than a mode flag on it, because it offers a materially weaker guarantee: CBC gives confidentiality only and does not authenticate. Keeping the types apart means a caller cannot reach CBC by accident, and the obligation to authenticate the IV and ciphertext separately is documented where it will be read. PKCS#7 padding is opt-in through EncryptPadded and DecryptPadded. Padding is a choice made by the surrounding protocol rather than a property of CBC, so Encrypt and Decrypt leave block-aligned input alone. The IV is always caller-supplied and is never prefixed to or stripped from the ciphertext, for the same reason. GenerateCBCIV is named to keep it clearly distinct from the GCM nonce that Cipher generates internally. The two are not interchangeable. The key check value logic moves into shared helpers so that a key reports the same value under either mode.
The PKCS#7 padded operation was chosen before the G+D CII specification was available, so it was never derived from a requirement. The CII data provider interface names its algorithm aes-256-cbc-iso2, and "ISO2" in card personalisation interfaces denotes ISO/IEC 9797-1 padding method 2: a single 0x80 marker followed by 0x00 filler to the block boundary. PKCS#7 is a different byte layout and must not be substituted merely because it also produces block-aligned output. EncryptPadded and DecryptPadded become EncryptISO9797M2Padded and DecryptISO9797M2Padded so a protocol requiring a different scheme, such as PKCS#7 or ISO 10126-2, cannot reach them by accident. Renaming is free because CBCCipher has not been released. The padded ciphertext is anchored to the NIST SP 800-38A F.2 vectors: CBC encrypts block by block, so appending a padding block cannot alter the preceding ciphertext, and the block-aligned NIST plaintext gains exactly one extra block. Tests also assert that PKCS#7 padding is rejected rather than silently accepted, and that messages ending in 0x80 or 0x00 still round trip.
|
Comment
You can also request review from a specific team by commenting 💡 If you see something that doesn't look right, check the configuration guide. |
|
/wise-review full |
|
/wise-review |
There was a problem hiding this comment.
🟡 Changes recommended
The padded CBC decrypt path currently returns detailed padding-validation errors directly, increasing the risk of callers accidentally exposing padding-oracle signals.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Changes: New feature (1)
This PR adds AES-CBC support to the shared Go crypto library to meet the G+D CII perso interface requirement (aes-256-cbc-iso2), including ISO/IEC 9797-1 method 2 padding helpers and associated test vectors.
Changes:
- Introduces
CBCCipherwith raw encrypt/decrypt APIs plus ISO9797 M2 padded variants. - Adds CBC key constructors (raw + hex) and
GenerateCBCIVfor per-message IV generation. - Refactors AES key check value (KCV) derivation so it can be shared between GCM and CBC, and documents CBC usage.
File summaries
| File | Description |
|---|---|
VERSION.txt |
Bumps library version to 1.14.0 for the new CBC feature. |
README.md |
Documents the new AES-CBC APIs and highlights the lack of built-in authentication. |
aes/aes_cipher.go |
Extracts and reuses shared AES KCV derivation/verification logic for GCM. |
aes/aes_cbc_factory.go |
Adds constructors for CBC keys and a helper to generate random 16-byte IVs. |
aes/aes_cbc_cipher.go |
Implements AES-CBC encrypt/decrypt plus ISO9797 M2 padded operations and KCV helpers. |
aes/iso9797m2.go |
Adds ISO/IEC 9797-1 method 2 padding/unpadding helpers. |
aes/iso9797m2_test.go |
Adds unit tests for ISO9797 M2 padding/unpadding and edge cases. |
aes/aes_cbc_cipher_test.go |
Adds NIST known-answer vector tests plus CBC/ISO9797 round-trip and validation tests. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
/request-review |
|
Success 🎉 The review request was sent to the following:
If you see something that doesn't look right, follow this doc to improve our slack channel mapping. Thank you! |
|
/wise-review full |
Context
Milestone 7.1 of Card Vending Machine Engineering.
The G+D CII perso interface requires
aes-256-cbc-iso2, while this library currently exposes AES-GCM only. This PR adds the AES-CBC operations needed by the manufacturing plugin and VHSM work that follows.This PR is limited to the shared crypto library. Key import, VHSM endpoints and CII request construction remain separate parts of milestone 7.
What changed
CBCCipherwith rawEncryptandDecryptmethods.EncryptISO9797M2PaddedandDecryptISO9797M2Paddedfor ISO/IEC 9797-1 method 2 padding:0x80, then zeroes to the next 16-byte boundary.GenerateCBCIVfor fresh 16-byte IVs.The generic constructors accept 16, 24 and 32-byte AES keys. The CII consumer will use a 32-byte AES-256 key.
API design
CBC is a separate type from the existing GCM
Cipherbecause CBC does not authenticate its output.The caller supplies the IV.
CBCCipherdoes not prefix or remove it from ciphertext, leaving protocol-specific framing to the consumer. Raw methods support already aligned input, while the named padded methods handle arbitrary input using the CII padding scheme.Verification
go test -race ./...go vet ./...