# v0.3 W2 KAT fixtures
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`].