Claude
Skills
Sign in
Back

crypto-primitive-selection

Included with Lifetime
$97 forever

Decision aid for choosing AEAD, KDF, MAC, and signature primitives — flags anti-patterns (CBC-without-MAC, ad-hoc KDF, key reuse, PBKDF2-on-high-entropy).

Ads & Marketing

What this skill does


# crypto-primitive-selection

Decision aid for cryptographic primitive choices. Use this skill when designing or reviewing systems that encrypt, authenticate, derive, or sign — and especially before writing any line of code that calls a low-level crypto API.

The skill does not pick a single product or library for you. It gives you a **suggested default** for the common case, a **vetted alternatives menu** with selection criteria, and a **research path** for when neither default nor menu fits your constraints.

## Triggers

Primary phrases are matched automatically from the description. Alternate expressions:

- "choose AEAD" / "which AEAD"
- "which KDF" / "password hashing"
- "encrypt with AES" / "AES-CBC" / "AES-GCM"
- "should I use HMAC"
- "sign vs MAC"
- "openssl enc" (any context)
- "is HMAC-SHA1 OK"
- "is PBKDF2 enough"
- "applied crypto review"

## When NOT to use this skill

- High-level protocol design (use a peer-reviewed protocol like TLS 1.3, Noise, or Signal — don't roll your own)
- Post-quantum migration planning (separate concern; consult NIST PQC selections)
- Network-layer threat modeling (handled by `sdlc-complete/skills/security-assessment`)

## Catalog Format

Every primitive section follows the same three-part pattern:

1. **Suggested default** — the right answer for the common case, with rationale
2. **Vetted alternatives menu** — when to pick something else, with selection criteria
3. **Research path** — how to evaluate newer or domain-specific options when nothing in the menu fits

The skill never hard-picks a vendor product. It describes properties; you choose against your constraints.

---

## Section 1: AEAD (Authenticated Encryption with Associated Data)

**Use when**: Encrypting data at rest or in flight where you also need to detect tampering. This is the default for ~95% of "encrypt this" tasks.

### Suggested default

**XChaCha20-Poly1305 via libsodium** (`crypto_secretstream_xchacha20poly1305_*` for streams, `crypto_aead_xchacha20poly1305_ietf_*` for one-shot).

Rationale:
- 192-bit nonces — random nonce generation is misuse-resistant (no birthday bound concerns for the lifetime of any realistic key)
- Audited C implementation (libsodium has been independently audited; tracks Bernstein/Aumasson reference)
- Broad language bindings (Python, Rust, Go, Node, Ruby, .NET, Swift — all wrap the same C lib)
- No hardware dependency — runs at acceptable speed in software on every architecture
- Streaming API via `secretstream` handles multi-chunk encryption with replay/reorder/truncation protection

### Vetted alternatives

| Primitive | Pick when |
|---|---|
| **AES-256-GCM** | Hardware AES-NI dominates and you need top throughput on x86_64/ARM with crypto extensions; OR you need FIPS 140-3 validation and your validated module exposes GCM but not ChaCha. Watch the 96-bit nonce — never reuse with the same key, use a counter not a random. |
| **AES-256-GCM-SIV (RFC 8452)** | You can't guarantee non-reuse of nonces (e.g., distributed system without a counter source). SIV is misuse-resistant against accidental reuse — degrades to revealing equality of plaintexts, not catastrophic loss. |
| **ChaCha20-Poly1305 IETF (RFC 8439)** | Same algorithm as XChaCha but 96-bit nonce. Pick when interoperating with TLS 1.3, WireGuard, or other IETF-spec stacks that mandate this exact construction. |
| **AES-256-CCM** | Constrained embedded environments where code size matters and only AES is in ROM. Use only in profile (CCM has tight nonce/length tradeoffs). |
| **age (file format)** | Encrypting files for asymmetric recipients (X25519 public keys or SSH keys). Don't reimplement; use the `age` reference tool or a library binding. |

### Research path for newer/domain-specific options

When the default and menu don't fit:

1. **CFRG drafts** at `datatracker.ietf.org/wg/cfrg/documents/` — the IRTF Crypto Forum vets new constructions before IETF/NIST adoption
2. **NIST CAVP validation list** (`csrc.nist.gov/projects/cryptographic-algorithm-validation-program`) — required if you need FIPS-validated software/hardware
3. **NIST Lightweight Crypto winners** (Ascon family, 2023) — prefer for tightly-constrained IoT
4. **SoK papers** — search for "Systematization of Knowledge: AEAD" on IACR ePrint; SoK papers summarize the landscape with attack tables
5. **Rule out**: anything labeled "experimental", "research preview", or with no public security analysis from a non-author. If the construction is one academic paper old, it's not production-ready.

### Anti-patterns (BLOCK on these)

- **CBC, CTR, OFB, CFB without a separate MAC.** Unauthenticated. Bit-flips are silently undetectable; padding oracles leak plaintext on decryption error paths. → **Rule: `no-unauthenticated-encryption`**
- **`openssl enc` without `-pbkdf2 -iter <N>`** (or similar explicit KDF flags). Defaults to a single-MD5-iteration KDF. → **Rule: `crypto-flag-verification`**
- **Reusing GCM nonces with the same key.** Catastrophic — recover the authentication key and forge arbitrary ciphertexts. Use a counter, not a random, when collision-likelihood matters.
- **Encrypt-then-truncate.** Truncating an AEAD ciphertext breaks the tag. If you need length-hiding, pad before encrypting, not after.

---

## Section 2: KDF (Key Derivation Function)

**Use when**: You have an Input Keying Material (IKM) and need to turn it into one or more cryptographic keys. The right KDF depends entirely on the **entropy class** of the IKM.

### Decision tree (READ FIRST)

```
What is the entropy class of your input?
│
├── HIGH ENTROGY (≥128 bits effective)
│   - Output of another KDF
│   - Hardware-derived secret (TPM, YubiKey HMAC, FIDO2 PRF)
│   - DH/ECDH shared secret
│   - Random key from CSPRNG
│   ↓
│   USE: HKDF-Extract + HKDF-Expand (RFC 5869)
│
└── LOW ENTROPY (passwords, passphrases, PINs, recovery codes)
    ↓
    USE: Argon2id (preferred) OR PBKDF2-HMAC-SHA-256 ≥600k iter (legacy/FIPS)
```

**The most common mistake** (review finding H1 in the motivating gap analysis): applying PBKDF2 with 100k iterations to a 256-bit hardware-derived secret. This **slows the defender** without slowing the attacker, because the attacker is not doing brute force on a 256-bit key — that's already infeasible. PBKDF2 only buys you anything when the input is brute-forceable. With a high-entropy input, use HKDF.

### Suggested defaults

| IKM entropy | Default | Rationale |
|---|---|---|
| High | **HKDF-SHA-256** (libsodium `crypto_kdf_*`) | RFC 5869, universally supported, fast, parametric in salt and info string |
| Low (interactive password) | **Argon2id** with `m=65536, t=3, p=4` (libsodium `crypto_pwhash_*` with `OPSLIMIT_INTERACTIVE`) | RFC 9106; memory-hard against GPU/ASIC attackers |
| Low (FIPS or legacy constraint) | **PBKDF2-HMAC-SHA-256** with ≥600,000 iterations (OWASP 2023) | RFC 8018; available everywhere; CPU-bound only |

### Vetted alternatives

| Primitive | Pick when |
|---|---|
| **scrypt** | You need memory-hardness but Argon2 isn't available in your runtime. Parameters: `N=2^17, r=8, p=1` for interactive, scale up for offline. |
| **bcrypt** | Legacy systems already using bcrypt. Don't introduce in greenfield. Cost factor ≥12; truncates passwords at 72 bytes (pre-hash if longer). |
| **HKDF-SHA-512** | Output keys longer than 8160 bits OR you specifically want SHA-512's domain. Default to SHA-256 otherwise. |
| **NIST SP 800-108 KBKDF (KDF in counter mode)** | FIPS-mandated environments where HKDF isn't approved. Functionally equivalent to HKDF-Expand for typical uses. |

### Required pattern: domain separation when deriving multiple keys

When one IKM produces multiple output keys (e.g., `enc_key` AND `mac_key`), use distinct `info` strings via HKDF-Expand. **Never reuse a single derived key for two purposes.** This is the fix for review finding B2:

```
prk     = HKDF-Extract(salt, ikm)
enc_key = HKDF-Expand(prk, info="app-aead-v1",   length=32)
mac_key = HKDF-Expand(prk, info="app-mac-v1", 

Related in Ads & Marketing