# 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

| File | Format | Generated by |
|---|---|---|
| `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.
