moai-security-encryption
Encryption patterns - AES-GCM, RSA, password hashing, envelope encryption
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install jg-chalk-io-nora-livekit-moai-security-encryption
Repository
Skill path: .claude/skills/moai-security-encryption
Encryption patterns - AES-GCM, RSA, password hashing, envelope encryption
Open repositoryBest for
Primary workflow: Analyze Data & AI.
Technical facets: Full Stack, Data / AI, Security.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: jg-chalk-io.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install moai-security-encryption into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/jg-chalk-io/Nora-LiveKit before adding moai-security-encryption to shared team environments
- Use moai-security-encryption for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: moai-security-encryption
version: 4.0.0
updated: 2025-11-20
status: stable
description: Encryption patterns - AES-GCM, RSA, password hashing, envelope encryption
allowed-tools: [Read, Bash, WebSearch, WebFetch]
---
# Encryption Security Expert
**Secure Data Encryption Patterns**
> **Focus**: AES-256-GCM, RSA-4096, Password Hashing (bcrypt/Argon2)
> **Standards**: NIST, OWASP, FIPS 140-2
---
## Overview
Production-grade encryption for data at rest and in transit.
### Core Encryption Types
1. **Symmetric**: AES-256-GCM (same key for encrypt/decrypt)
2. **Asymmetric**: RSA-4096 (public/private key pair)
3. **Password Hashing**: bcrypt, Argon2id (one-way)
4. **Envelope Encryption**: Data encrypted with DEK, DEK encrypted with KEK
---
## Quick Start
### 1. Symmetric Encryption (AES-256-GCM)
For encrypting data at rest (files, database fields).
**Use Cases**: Database columns, file storage, session data
**Key Points**:
- 256-bit key
- GCM mode (authenticated encryption)
- Unique IV per encryption
See: [examples.md](./examples.md#aes-gcm-encryption)
### 2. Asymmetric Encryption (RSA)
For key exchange and digital signatures.
**Use Cases**: HTTPS, JWT signing, key distribution
**Key Points**:
- 4096-bit keys (2025 standard)
- OAEP padding
- Public key for encryption, private for decryption
See: [examples.md](./examples.md#rsa-encryption)
### 3. Password Hashing
For storing user passwords securely.
**Use Cases**: User authentication, API keys
**Algorithms**: bcrypt (recommended), Argon2id (modern)
**Key Points**:
- Never reversible
- Salt automatically included
- Cost factor: 12+ (2025)
See: [examples.md](./examples.md#password-hashing)
### 4. Envelope Encryption
For securing large datasets with key rotation.
**Pattern**:
1. Generate Data Encryption Key (DEK)
2. Encrypt data with DEK
3. Encrypt DEK with Key Encryption Key (KEK)
4. Store encrypted data + encrypted DEK
See: [examples.md](./examples.md#envelope-encryption)
---
## Encryption Decision Tree
```
Need to encrypt?
├─ Password? → bcrypt or Argon2id
├─ Large file/data? → AES-256-GCM (symmetric)
├─ Key exchange? → RSA-4096 (asymmetric)
└─ Multi-key management? → Envelope Encryption
```
---
## Best Practices
1. **Key Management**: Never hardcode keys, use environment variables or KMS
2. **Random IVs**: Generate new IV for each encryption
3. **Authenticated Encryption**: Use GCM mode (prevents tampering)
4. **Key Rotation**: Rotate keys annually or after breach
5. **Secure Storage**: Store keys separately from encrypted data
---
## Security Checklist
- [ ] **Algorithm**: AES-256-GCM or RSA-4096?
- [ ] **Keys**: Stored securely (not in code)?
- [ ] **IVs**: Unique per encryption?
- [ ] **Mode**: Authenticated (GCM, not ECB)?
- [ ] **Rotation**: Key rotation policy defined?
---
## Related Skills
- `moai-security-api`: API encryption (TLS)
- `moai-security-auth`: Token encryption
- `moai-cloud-aws-advanced`: AWS KMS integration
---
## Additional Resources
- [examples.md](./examples.md): Implementation code
- [reference.md](./reference.md): NIST standards, algorithms
---
**Last Updated**: 2025-11-20
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### examples.md
```markdown
# Encryption Examples
Practical encryption implementations for Python and Node.js.
---
## AES-GCM Encryption
### Python Implementation
```python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2
import os
import base64
class AESEncryption:
"""AES-256-GCM encryption wrapper."""
def __init__(self, key: bytes):
"""Initialize with 256-bit key."""
if len(key) != 32: # 256 bits = 32 bytes
raise ValueError("Key must be 32 bytes for AES-256")
self.cipher = AESGCM(key)
@classmethod
def from_password(cls, password: str, salt: bytes = None):
"""Derive key from password using PBKDF2."""
if salt is None:
salt = os.urandom(16)
kdf = PBKDF2(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000, # NIST recommendation
)
key = kdf.derive(password.encode())
return cls(key), salt
def encrypt(self, plaintext: bytes) -> tuple[bytes, bytes]:
"""Encrypt data and return (ciphertext, nonce)."""
nonce = os.urandom(12) # 96 bits for GCM
ciphertext = self.cipher.encrypt(nonce, plaintext, None)
return ciphertext, nonce
def decrypt(self, ciphertext: bytes, nonce: bytes) -> bytes:
"""Decrypt data."""
plaintext = self.cipher.decrypt(nonce, ciphertext, None)
return plaintext
# Usage
key = AESGCM.generate_key(bit_length=256)
aes = AESEncryption(key)
# Encrypt
message = b"Sensitive data"
ciphertext, nonce = aes.encrypt(message)
# Decrypt
plaintext = aes.decrypt(ciphertext, nonce)
assert plaintext == message
# Store encrypted data
stored_data = {
"ciphertext": base64.b64encode(ciphertext).decode(),
"nonce": base64.b64encode(nonce).decode(),
}
```
### Node.js Implementation
```javascript
const crypto = require("crypto");
class AESEncryption {
constructor(key) {
if (key.length !== 32) {
throw new Error("Key must be 32 bytes for AES-256");
}
this.key = key;
}
static fromPassword(password, salt = null) {
if (!salt) {
salt = crypto.randomBytes(16);
}
const key = crypto.pbkdf2Sync(
password,
salt,
100000, // iterations
32, // key length
"sha256"
);
return { cipher: new AESEncryption(key), salt };
}
encrypt(plaintext) {
const iv = crypto.randomBytes(12); // 96 bits for GCM
const cipher = crypto.createCipheriv("aes-256-gcm", this.key, iv);
let ciphertext = cipher.update(plaintext, "utf8", "hex");
ciphertext += cipher.final("hex");
const authTag = cipher.getAuthTag();
return {
ciphertext,
iv: iv.toString("hex"),
authTag: authTag.toString("hex"),
};
}
decrypt(ciphertext, iv, authTag) {
const decipher = crypto.createDecipheriv(
"aes-256-gcm",
this.key,
Buffer.from(iv, "hex")
);
decipher.setAuthTag(Buffer.from(authTag, "hex"));
let plaintext = decipher.update(ciphertext, "hex", "utf8");
plaintext += decipher.final("utf8");
return plaintext;
}
}
// Usage
const key = crypto.randomBytes(32);
const aes = new AESEncryption(key);
const message = "Sensitive data";
const encrypted = aes.encrypt(message);
const decrypted = aes.decrypt(
encrypted.ciphertext,
encrypted.iv,
encrypted.authTag
);
console.log(decrypted === message); // true
```
---
## RSA Encryption
### Python Implementation
```python
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
class RSAEncryption:
"""RSA-4096 encryption wrapper."""
@staticmethod
def generate_keypair():
"""Generate RSA-4096 key pair."""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096, # 2025 standard
)
public_key = private_key.public_key()
return private_key, public_key
@staticmethod
def encrypt(public_key, plaintext: bytes) -> bytes:
"""Encrypt with public key."""
ciphertext = public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext
@staticmethod
def decrypt(private_key, ciphertext: bytes) -> bytes:
"""Decrypt with private key."""
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return plaintext
@staticmethod
def save_private_key(private_key, filename: str, password: bytes = None):
"""Save private key to file (encrypted if password provided)."""
encryption = serialization.BestAvailableEncryption(password) if password else serialization.NoEncryption()
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=encryption
)
with open(filename, 'wb') as f:
f.write(pem)
@staticmethod
def load_private_key(filename: str, password: bytes = None):
"""Load private key from file."""
with open(filename, 'rb') as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=password
)
return private_key
# Usage
private_key, public_key = RSAEncryption.generate_keypair()
# Encrypt
message = b"Secret message"
ciphertext = RSAEncryption.encrypt(public_key, message)
# Decrypt
plaintext = RSAEncryption.decrypt(private_key, ciphertext)
assert plaintext == message
# Save keys
RSAEncryption.save_private_key(private_key, 'private.pem', password=b'strongpassword')
```
---
## Password Hashing
### bcrypt (Python)
```python
import bcrypt
class PasswordHasher:
"""Secure password hashing with bcrypt."""
@staticmethod
def hash_password(password: str, rounds: int = 12) -> str:
"""Hash password with bcrypt."""
salt = bcrypt.gensalt(rounds=rounds)
hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed.decode('utf-8')
@staticmethod
def verify_password(password: str, hashed: str) -> bool:
"""Verify password against hash."""
return bcrypt.checkpw(
password.encode('utf-8'),
hashed.encode('utf-8')
)
# Usage
hasher = PasswordHasher()
# Hash password
password = "MySecurePassword123!"
hashed = hasher.hash_password(password)
# Verify
is_valid = hasher.verify_password(password, hashed) # True
is_invalid = hasher.verify_password("wrong", hashed) # False
```
### Argon2 (Python)
```python
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
class Argon2Hasher:
"""Modern password hashing with Argon2id."""
def __init__(self):
self.ph = PasswordHasher(
time_cost=3, # iterations
memory_cost=65536, # 64 MB
parallelism=4, # threads
hash_len=32, # output length
salt_len=16, # salt length
)
def hash_password(self, password: str) -> str:
"""Hash password with Argon2id."""
return self.ph.hash(password)
def verify_password(self, password: str, hashed: str) -> bool:
"""Verify password against hash."""
try:
self.ph.verify(hashed, password)
# Check if rehash needed (parameters changed)
if self.ph.check_needs_rehash(hashed):
# Rehash with new parameters
return True, self.hash_password(password)
return True, None
except VerifyMismatchError:
return False, None
# Usage
hasher = Argon2Hasher()
password = "MySecurePassword123!"
hashed = hasher.hash_password(password)
is_valid, new_hash = hasher.verify_password(password, hashed)
if new_hash:
# Update database with new_hash
pass
```
### bcrypt (Node.js)
```javascript
const bcrypt = require("bcrypt");
class PasswordHasher {
static async hashPassword(password, rounds = 12) {
const salt = await bcrypt.genSalt(rounds);
const hashed = await bcrypt.hash(password, salt);
return hashed;
}
static async verifyPassword(password, hashed) {
return await bcrypt.compare(password, hashed);
}
}
// Usage
(async () => {
const password = "MySecurePassword123!";
const hashed = await PasswordHasher.hashPassword(password);
const isValid = await PasswordHasher.verifyPassword(password, hashed); // true
const isInvalid = await PasswordHasher.verifyPassword("wrong", hashed); // false
})();
```
---
## Envelope Encryption
### Python Implementation
```python
class EnvelopeEncryption:
"""Envelope encryption pattern for large data."""
def __init__(self, kek: bytes):
"""Initialize with Key Encryption Key (KEK)."""
self.kek_cipher = AESGCM(kek)
def encrypt_data(self, plaintext: bytes) -> dict:
"""
Encrypt data using envelope encryption.
Returns {
'encrypted_data': encrypted with DEK,
'encrypted_dek': DEK encrypted with KEK,
'data_nonce': nonce for data,
'dek_nonce': nonce for DEK
}
"""
# Generate Data Encryption Key (DEK)
dek = AESGCM.generate_key(bit_length=256)
dek_cipher = AESGCM(dek)
# Encrypt data with DEK
data_nonce = os.urandom(12)
encrypted_data = dek_cipher.encrypt(data_nonce, plaintext, None)
# Encrypt DEK with KEK
dek_nonce = os.urandom(12)
encrypted_dek = self.kek_cipher.encrypt(dek_nonce, dek, None)
return {
'encrypted_data': encrypted_data,
'encrypted_dek': encrypted_dek,
'data_nonce': data_nonce,
'dek_nonce': dek_nonce,
}
def decrypt_data(self, envelope: dict) -> bytes:
"""Decrypt envelope-encrypted data."""
# Decrypt DEK with KEK
dek = self.kek_cipher.decrypt(
envelope['dek_nonce'],
envelope['encrypted_dek'],
None
)
# Decrypt data with DEK
dek_cipher = AESGCM(dek)
plaintext = dek_cipher.decrypt(
envelope['data_nonce'],
envelope['encrypted_data'],
None
)
return plaintext
# Usage
kek = AESGCM.generate_key(bit_length=256) # Master key
envelope_enc = EnvelopeEncryption(kek)
# Encrypt large file
large_data = b"Large dataset..." * 1000
envelope = envelope_enc.encrypt_data(large_data)
# Store envelope (can rotate KEK without re-encrypting data)
import json
stored_envelope = {
k: base64.b64encode(v).decode() if isinstance(v, bytes) else v
for k, v in envelope.items()
}
# Decrypt
plaintext = envelope_enc.decrypt_data(envelope)
assert plaintext == large_data
```
### AWS KMS Integration (Python)
```python
import boto3
import base64
class AWSEnvelopeEncryption:
"""Envelope encryption using AWS KMS."""
def __init__(self, kms_key_id: str):
self.kms = boto3.client('kms')
self.kms_key_id = kms_key_id
def encrypt_data(self, plaintext: bytes) -> dict:
"""Encrypt using AWS KMS for KEK."""
# Generate DEK using KMS
response = self.kms.generate_data_key(
KeyId=self.kms_key_id,
KeySpec='AES_256'
)
dek_plaintext = response['Plaintext']
dek_encrypted = response['CiphertextBlob']
# Encrypt data with DEK
cipher = AESGCM(dek_plaintext)
nonce = os.urandom(12)
encrypted_data = cipher.encrypt(nonce, plaintext, None)
return {
'encrypted_data': encrypted_data,
'encrypted_dek': dek_encrypted,
'nonce': nonce,
}
def decrypt_data(self, envelope: dict) -> bytes:
"""Decrypt using AWS KMS."""
# Decrypt DEK using KMS
response = self.kms.decrypt(
CiphertextBlob=envelope['encrypted_dek']
)
dek_plaintext = response['Plaintext']
# Decrypt data with DEK
cipher = AESGCM(dek_plaintext)
plaintext = cipher.decrypt(
envelope['nonce'],
envelope['encrypted_data'],
None
)
return plaintext
# Usage (requires AWS credentials)
kms_enc = AWSEnvelopeEncryption('your-kms-key-id')
data = b"Sensitive data"
envelope = kms_enc.encrypt_data(data)
plaintext = kms_enc.decrypt_data(envelope)
```
---
## File Encryption
### Encrypt File (Python)
```python
def encrypt_file(input_path: str, output_path: str, password: str):
"""Encrypt file with AES-256-GCM."""
# Derive key from password
aes, salt = AESEncryption.from_password(password)
# Read file
with open(input_path, 'rb') as f:
plaintext = f.read()
# Encrypt
ciphertext, nonce = aes.encrypt(plaintext)
# Write encrypted file
with open(output_path, 'wb') as f:
f.write(salt) # 16 bytes
f.write(nonce) # 12 bytes
f.write(ciphertext)
def decrypt_file(input_path: str, output_path: str, password: str):
"""Decrypt file."""
# Read encrypted file
with open(input_path, 'rb') as f:
salt = f.read(16)
nonce = f.read(12)
ciphertext = f.read()
# Derive key
aes, _ = AESEncryption.from_password(password, salt)
# Decrypt
plaintext = aes.decrypt(ciphertext, nonce)
# Write decrypted file
with open(output_path, 'wb') as f:
f.write(plaintext)
# Usage
encrypt_file('secret.txt', 'secret.enc', 'MyPassword123!')
decrypt_file('secret.enc', 'secret_decrypted.txt', 'MyPassword123!')
```
---
**See also**: [reference.md](./reference.md) for NIST standards and algorithm details.
```
### reference.md
```markdown
# Encryption Reference
NIST standards, algorithm specifications, and security best practices.
---
## Encryption Algorithms
### AES-GCM (Advanced Encryption Standard - Galois/Counter Mode)
**Specification**: NIST SP 800-38D
**Parameters**:
- Key size: 256 bits (32 bytes)
- IV/Nonce: 96 bits (12 bytes) - MUST be unique per encryption
- Tag size: 128 bits (16 bytes) - authentication tag
**Security Properties**:
- Confidentiality: ✅ (symmetric encryption)
- Integrity: ✅ (authenticated encryption)
- Forward secrecy: ❌ (requires key rotation)
**Performance**: ~1-2 GB/s (AES-NI hardware acceleration)
**Use Cases**: Database encryption, file encryption, session data
**Compliance**: FIPS 140-2, PCI DSS, HIPAA
---
### RSA (Rivest-Shamir-Adleman)
**Specification**: NIST FIPS 186-4
**Key Sizes** (2025 recommendations):
- 2048 bits: Legacy (not recommended for new systems)
- 3072 bits: Minimum
- 4096 bits: **Recommended**
**Padding Schemes**:
- **OAEP** (Optimal Asymmetric Encryption Padding) - ✅ Recommended
- PKCS#1 v1.5 - ❌ Deprecated (vulnerable to padding oracle attacks)
**Security Properties**:
- Confidentiality: ✅ (asymmetric encryption)
- Digital signatures: ✅
- Key exchange: ✅
**Performance**: ~1000x slower than AES (use for key exchange, not bulk data)
**Use Cases**: TLS/SSL, digital signatures, key wrapping
**Compliance**: FIPS 140-2, Common Criteria
---
### bcrypt
**Specification**: Based on Blowfish cipher
**Parameters**:
- Cost factor (rounds): 10-14 (2025: **12 recommended**)
- Salt: 128 bits (automatically generated)
- Output: 192 bits (24 bytes)
**Security Properties**:
- Adaptive: Cost can increase over time
- Salt: Unique per password
- Slow: Designed to be computationally expensive (~100-500ms)
**Formula**: `2^cost` iterations
**Use Cases**: Password storage (NOT for encryption)
**Resistance**:
- Brute force: ✅ (high cost factor)
- Rainbow tables: ✅ (unique salts)
- GPU attacks: ⚠️ (partially resistant)
---
### Argon2id
**Specification**: RFC 9106 (2021)
**Parameters**:
- Time cost (iterations): 3
- Memory cost: 64 MB (65536 KB)
- Parallelism: 4 threads
- Salt: 128 bits
- Output: 256 bits
**Variants**:
- Argon2d: Resistant to GPU attacks, vulnerable to side-channel
- Argon2i: Resistant to side-channel, weaker against GPU
- **Argon2id**: ✅ Hybrid (recommended)
**Security Properties**:
- Memory-hard: Requires significant RAM
- Side-channel resistant: Constant-time operations
- GPU/ASIC resistant: ✅ (best among password hashing algorithms)
**Use Cases**: Password storage (modern replacement for bcrypt)
**Compliance**: PHC (Password Hashing Competition) winner
---
## Key Management
### Key Derivation (PBKDF2)
**Specification**: NIST SP 800-132
**Parameters**:
- Iterations: 100,000+ (2025 recommendation)
- Hash function: SHA-256 or SHA-512
- Salt: 128 bits minimum
- Output length: 256 bits
**Use Case**: Derive encryption key from password
```python
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2
from cryptography.hazmat.primitives import hashes
kdf = PBKDF2(
algorithm=hashes.SHA256(),
length=32, # 256 bits
salt=salt,
iterations=600000, # OWASP 2023 recommendation
)
key = kdf.derive(password.encode())
```
---
### Key Rotation
**Frequency Recommendations**:
- Symmetric keys (AES): Annually or after 2^32 encryptions
- Asymmetric keys (RSA): Every 2-3 years
- Password hashes: On credential change or breach
**Rotation Process**:
1. Generate new key (KEK₂)
2. Decrypt DEK with old KEK₁
3. Re-encrypt DEK with new KEK₂
4. Update key reference in database
5. Securely delete KEK₁
**Graceful Migration**:
```python
def migrate_encryption(old_kek, new_kek):
# Decrypt with old key
plaintext_dek = decrypt(encrypted_dek, old_kek)
# Re-encrypt with new key
new_encrypted_dek = encrypt(plaintext_dek, new_kek)
# Update database
db.update(encrypted_dek=new_encrypted_dek, key_version=2)
```
---
## Security Standards
### NIST Recommendations (SP 800-57)
**Key Sizes** (Through 2030):
| Algorithm | Key Size | Security Level |
|-----------|----------|----------------|
| AES | 128 bits | 128-bit |
| AES | **256 bits** | **256-bit** ✅ |
| RSA | 2048 bits | 112-bit |
| RSA | 3072 bits | 128-bit |
| RSA | **4096 bits** | **152-bit** ✅ |
| ECC | 256 bits | 128-bit |
| ECC | 384 bits | 192-bit |
---
### OWASP Cryptographic Storage Cheat Sheet
**DO**:
- ✅ Use AES-256-GCM for symmetric encryption
- ✅ Use RSA-4096 or ECC (P-384) for asymmetric
- ✅ Use bcrypt (cost 12+) or Argon2id for passwords
- ✅ Generate cryptographically secure random IVs/salts
- ✅ Use authenticated encryption (GCM, not CBC)
- ✅ Implement key rotation policy
- ✅ Store keys separately from encrypted data
**DON'T**:
- ❌ Use MD5 or SHA-1 for hashing (broken)
- ❌ Use ECB mode (insecure)
- ❌ Reuse IVs/nonces
- ❌ Roll your own crypto
- ❌ Store keys with encrypted data
- ❌ Use weak random number generators (e.g., `Math.random()`)
---
### Compliance Mappings
| Standard | Requirement | Algorithm |
| -------------- | ----------------------- | ------------------ |
| **PCI DSS** | Data at rest encryption | AES-256 |
| **HIPAA** | PHI encryption | AES-256, RSA-2048+ |
| **GDPR** | Pseudonymization | AES-256-GCM |
| **FIPS 140-2** | Approved algorithms | AES, RSA, SHA-2 |
| **SOC 2** | Encryption in transit | TLS 1.3 |
---
## Attack Vectors
### Known Attacks
**Padding Oracle Attack** (CBC mode):
- **Vulnerable**: AES-CBC without authentication
- **Mitigation**: Use GCM mode (authenticated encryption)
**Timing Attacks** (RSA):
- **Vulnerable**: Unpadded RSA, constant-time comparison
- **Mitigation**: Use OAEP padding, constant-time operations
**Brute Force** (Weak passwords):
- **Vulnerable**: Low bcrypt cost (<10)
- **Mitigation**: Cost 12+, enforce strong passwords
**Rainbow Tables** (Unsalted hashes):
- **Vulnerable**: `SHA-256(password)` without salt
- **Mitigation**: Use bcrypt/Argon2 (automatic salting)
---
## Entropy Requirements
**Random Number Generation**:
- **Cryptographic**: `os.urandom()` (Python), `crypto.randomBytes()` (Node.js)
- **NOT cryptographic**: `random.random()` (Python), `Math.random()` (JavaScript)
**Entropy Sources**:
- `/dev/urandom` (Linux)
- `CryptGenRandom` (Windows)
- Hardware RNG (TPM)
**Minimum Entropy**:
- Symmetric key (AES-256): 256 bits
- Salt: 128 bits
- IV/Nonce: 96 bits (GCM)
- Session token: 128 bits
```python
import secrets
# Cryptographically secure random
key = secrets.token_bytes(32) # 256 bits
token = secrets.token_urlsafe(32) # URL-safe token
```
---
## Quantum Resistance
### Post-Quantum Cryptography
**NIST PQC Selected Algorithms** (2022):
- **CRYSTALS-Kyber**: Key encapsulation
- **CRYSTALS-Dilithium**: Digital signatures
- **SPHINCS+**: Stateless hash-based signatures
**Timeline**:
- 2025-2030: Transition period
- 2030+: Quantum computers may break RSA/ECC
**Recommendation**: Plan for cryptographic agility (ability to switch algorithms)
---
## Tools & Libraries
### Python
```bash
pip install cryptography # Recommended
pip install pycryptodome # Alternative
pip install argon2-cffi # Passw hashing
```
### Node.js
```bash
npm install crypto # Built-in
npm install bcrypt # Password hashing
npm install argon2 # Modern hashing
```
### Verification
```bash
# Test AES-GCM support
openssl enc -aes-256-gcm -P
# Generate RSA key pair
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out public.pem
```
---
**See also**: [SKILL.md](./SKILL.md) for overview and [examples.md](./examples.md) for implementations.
```