Skip to content

feat: add AES-CBC support - #29

Merged
keithfong94 merged 4 commits into
masterfrom
aes-cbc
Sep 4, 2026
Merged

keithfong94 merged 4 commits into
masterfrom
aes-cbc

Conversation

@keithfong94

@keithfong94 keithfong94 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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

  • Add CBCCipher with raw Encrypt and Decrypt methods.
  • Add EncryptISO9797M2Padded and DecryptISO9797M2Padded for ISO/IEC 9797-1 method 2 padding: 0x80, then zeroes to the next 16-byte boundary.
  • Add constructors for raw and hex-encoded AES keys.
  • Add GenerateCBCIV for fresh 16-byte IVs.
  • Share AES key check value logic between GCM and CBC.
  • Document CBC usage and bump the version to 1.14.0.

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 Cipher because CBC does not authenticate its output.

The caller supplies the IV. CBCCipher does 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

  • AES-CBC encryption and decryption against the official NIST SP 800-38A Appendix F.2 known-answer values for AES-128, AES-192 and AES-256
  • ISO 9797 method 2 boundary and malformed-padding cases
  • Invalid key, IV and block lengths
  • Input mutation checks
  • KCV compatibility with the existing GCM type
  • go test -race ./...
  • go vet ./...
  • AES package coverage: 93.6%
  • GitHub Build & Test workflow passes

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.
@keithfong94 keithfong94 self-assigned this Sep 3, 2026
@keithfong94 keithfong94 added the change:standard Not an emergency or impactful change label Sep 3, 2026
@keithfong94
keithfong94 marked this pull request as ready for review September 3, 2026 08:47
@keithfong94
keithfong94 requested a review from a team as a code owner September 3, 2026 08:47
Copilot AI lite review requested due to automatic review settings September 3, 2026 08:47
@platon-github-app-production

Copy link
Copy Markdown

Comment /request-review to automatically request reviews from the following teams:

You can also request review from a specific team by commenting /request-review team-name, or you can add a description with --notes "<message>"

💡 If you see something that doesn't look right, check the configuration guide.

@keithfong94

Copy link
Copy Markdown
Contributor Author

/wise-review full

@keithfong94

Copy link
Copy Markdown
Contributor Author

/wise-review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 CBCCipher with raw encrypt/decrypt APIs plus ISO9797 M2 padded variants.
  • Adds CBC key constructors (raw + hex) and GenerateCBCIV for 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.

Comment thread aes/aes_cbc_cipher.go
@keithfong94

Copy link
Copy Markdown
Contributor Author

/request-review

@platon-github-app-production

Copy link
Copy Markdown

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!

@keithfong94

Copy link
Copy Markdown
Contributor Author

/wise-review full

@keithfong94
keithfong94 merged commit 6cec361 into master Sep 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:standard Not an emergency or impactful change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants