# Integration test fixtures
Binary KAT vectors + reference oracle harnesses for the v0.3+ wire-
format / codec / AEAD work.
## v0.3 W2 — PEM / PKCS#8 / SPKI / SEC1
Binary KAT vectors for the v0.3 W2 PEM / PKCS#8 / SPKI / SEC1 codecs.
These files are the **ground truth** for cross-validation against
gmssl 3.1.1 — committed so CI runners that lack gmssl still see the
regression vectors. (Q7.9 decision; binary files chosen over
`hex_literal` blocks for reviewability of the ~600-byte encrypted
PKCS#8 blob.)
## Contents
| `v0_3-sm2-spki.pem` | RFC 5280 SubjectPublicKeyInfo (PEM-armored) | `gmssl sm2keygen -pubout` |
| `v0_3-sm2-pkcs8-encrypted.pem` | RFC 5958 EncryptedPrivateKeyInfo (PEM-armored), PBES2 + PBKDF2-HMAC-SM3 + SM4-CBC | `gmssl sm2keygen -pass passw0rd -out` |
The two files form a **matched pair**: the SPKI carries the public
component of the same key whose private scalar lives (encrypted)
inside the PKCS#8 blob. The KAT test cross-checks that:
1. `pkcs8::decrypt(encrypted, b"passw0rd")` recovers an `Sm2PrivateKey`.
2. `spki::decode(public_der)` recovers an `Sm2PublicKey`.
3. The recovered public key equals the private key's `public_key()`.
## Regen recipe (auditor-reproducible)
```bash
# Requires gmssl 3.1.1 on $PATH.
gmssl sm2keygen \
-pass passw0rd \
-out v0_3-sm2-pkcs8-encrypted.pem \
-pubout v0_3-sm2-spki.pem
```
The generated keys are **non-deterministic** (gmssl seeds the curve
scalar from `OsRng`); each `sm2keygen` produces a new key. The
fixtures committed here are the output of one such run on
2026-05-11. To rotate them, re-run the recipe and update both files
together (the SPKI and PKCS#8 blob must stay paired). No other code
changes needed: the KAT test re-derives the expected public point
from the decrypted private key, so the assertions hold for any
matched (priv, pub) pair gmssl produces.
## Encryption parameters (decoded)
The encrypted PKCS#8 blob committed here uses gmssl 3.1.1's defaults:
- **Salt:** 16 bytes, randomly chosen at keygen time.
- **Iterations:** 65,536 (`0x010000`).
- **Key derivation:** PBKDF2-HMAC-SM3, key length 16 bytes.
- **Encryption scheme:** SM4-CBC with a randomly chosen 16-byte IV.
- **Outer wrapper:** PBES2 (`1.2.840.113549.1.5.13`).
These match the structure that `pkcs8::encrypt` emits in the
`gmcrypto-core` Rust path, and exercise the full PBES2 parameter
parser in `pkcs8::parse_encrypted_blob`.
## Password
`passw0rd` (8 bytes ASCII). Picked deliberately weak so the KAT test
runs fast at gmssl's default 65,536 iterations (<100 ms in debug
builds). Production callers should pick passwords with substantially
more entropy and **at least** OWASP's 2024 PBKDF2 baseline of 600,000
iterations, per the guidance in [`crate::kdf::pbkdf2_hmac_sm3`].
## v0.8 W3 — SM4-CCM reference oracle
`sm4_ccm_oracle.c` is a ~80-line C harness that calls OpenSSL 3.x's
EVP `SM4-CCM` cipher (OID `1.2.156.10197.1.104.9`, GB/T 0009 /
RFC 8998). Used to generate the static KAT vectors embedded in
`tests/sm4_ccm_kat.rs`.
gmssl 3.1.1's `sm4` subcommand does not ship `-ccm` (it has `-cbc`,
`-ctr`, `-gcm`, `-cbc_sm3_hmac`, `-ctr_sm3_hmac`), so the interop-
test approach used for SM4-CBC / SM4-CTR / SM4-GCM doesn't apply.
OpenSSL is the vendor-neutral fallback per the W0 deliverable
[`docs/v0.8-ccm-kat-sourcing.md`].
### Build
```bash
cc -O2 -Wall -I$(brew --prefix openssl@3)/include sm4_ccm_oracle.c \
$(brew --prefix openssl@3)/lib/libcrypto.dylib -o sm4_ccm_oracle
```
(On Linux, replace `$(brew --prefix openssl@3)` with the system
OpenSSL install path; `pkg-config --cflags --libs libcrypto` is the
portable invocation.)
### Run
```bash
# Encrypt: print "<ciphertext-hex> <tag-hex>"
./sm4_ccm_oracle enc <key-hex> <nonce-hex> <aad-hex> <pt-hex> <tag-len>
# Decrypt: print "<plaintext-hex>" or "TAG_FAIL"
./sm4_ccm_oracle dec <key-hex> <nonce-hex> <aad-hex> <ct-hex> <tag-hex>
```
### Re-generating the KAT fixtures
The eight scenarios committed inline in `tests/sm4_ccm_kat.rs` can be
regenerated by feeding the oracle the (key, nonce, aad, pt, tag_len)
tuples documented in that file's module docstring. The oracle is
deterministic; re-running it on the same inputs produces byte-
identical output. Any drift between the inline vectors and the
oracle output indicates either an OpenSSL behavior change or a
local toolchain bug.