Skip to content
Back to skills

Minimal

ASecurity

Choose the right cryptographic primitive for a job, and use it with the parameters that make it safe. Never design your own.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 10, 2026
securitypythongonodegitsecurity

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add snoodleboot-io/prompticorn --skill minimal --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Minimal?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Minimal
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/snoodleboot-io-minimal-d96a73f0/badge)](https://www.skillsdirectory.com/skills/snoodleboot-io-minimal-d96a73f0)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Cryptography Fundamentals (Minimal)

## Purpose
Choose the right cryptographic primitive for a job, and use it with the parameters that make it safe. Never design your own.

## Core Techniques

### 1. Encrypt With AEAD, Not Raw Ciphers
Authenticated Encryption with Associated Data gives confidentiality *and* integrity in one step. Unauthenticated ciphertext is malleable — an attacker who cannot read it can still flip bits in it.

```python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)                       # 96-bit nonce, MUST be unique per key
ct = aesgcm.encrypt(nonce, plaintext, b"user:42")   # 3rd arg = associated data
pt = aesgcm.decrypt(nonce, ct, b"user:42")          # raises InvalidTag if tampered
```

Store the nonce alongside the ciphertext — it is not secret, only unique.

### 2. Never Reuse a Nonce With AES-GCM
Nonce reuse under the same key is *catastrophic*, not merely weak. Two messages under the same (key, nonce) leak the XOR of their plaintexts and allow recovery of the GHASH authentication subkey — the attacker can then forge arbitrary valid ciphertexts for that key.

- Random 96-bit nonces are safe up to roughly 2^32 messages per key.
- If you cannot guarantee uniqueness, use XChaCha20-Poly1305 (192-bit nonce) or AES-GCM-SIV, which degrade gracefully on repeat.

### 3. Never Use ECB
ECB encrypts each block independently, so identical plaintext blocks produce identical ciphertext blocks. Structure survives encryption — the classic "encrypted penguin" is still recognisably a penguin. Use GCM, or CBC with a separate HMAC if a legacy protocol forces it.

### 4. Match the Hash to the Job
| Need | Use | Not |
|---|---|---|
| Content integrity / digest | SHA-256, SHA-3, BLAKE2 | MD5, SHA-1 (collisions are practical) |
| Password verifier | argon2id, bcrypt, scrypt | any plain hash |
| Keyed integrity | HMAC-SHA256 | `sha256(key + msg)` |
| Derive keys from a key | HKDF | ad-hoc concatenation |

Passwords need a *slow, memory-hard* function; a GPU does on the order of 10^10 SHA-256/sec.

### 5. Use Asymmetric Crypto for Key Agreement and Signing
```python
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

priv = X25519PrivateKey.generate()
shared = priv.exchange(peer_public_key)      # raw DH output — NOT a key yet
key = HKDF(algorithm=SHA256(), length=32, salt=None,
           info=b"handshake v1").derive(shared)
```
Always run the raw shared secret through a KDF: it is not uniformly random. Use X25519 for key agreement, Ed25519 for signatures, RSA (≥ 3072-bit, OAEP/PSS — never PKCS#1 v1.5) only for interop.

### 6. Get Randomness From the OS CSPRNG
`os.urandom` / `secrets` (Python), `crypto.randomBytes` (Node), `crypto/rand` (Go). Never `random`, `Math.random`, `rand()`, or a timestamp seed — those are predictable from a handful of outputs.

### 7. Compare Secrets in Constant Time
```python
import hmac
hmac.compare_digest(expected_mac, provided_mac)   # not ==
```
`==` short-circuits on the first differing byte, leaking the match length through timing.

## Warning Signs

- A counter, timestamp, or fixed value used as an AES-GCM nonce
- `AES.new(key, AES.MODE_ECB)` anywhere in the codebase
- MD5 or SHA-1 used for anything security-relevant
- A raw ECDH/X25519 output used directly as an encryption key
- Encryption with no authentication tag or MAC (CBC or CTR alone)
- Custom "encryption" built from XOR, base64, or a home-grown cipher
- Keys or IVs hardcoded in source, or committed to git
- `==` used to compare tokens, MACs, or signatures
- RSA with PKCS#1 v1.5 padding, or keys under 2048 bits

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…