Back to skills
SkillHub ClubAnalyze Data & AIFull StackData / AISecurity

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.

Stars
0
Hot score
74
Updated
March 20, 2026
Overall rating
C0.5
Composite score
0.5
Best-practice grade
C64.8

Install command

npx @skill-hub/cli install jg-chalk-io-nora-livekit-moai-security-encryption
encryptionsecuritycryptographydata-protection

Repository

jg-chalk-io/Nora-LiveKit

Skill path: .claude/skills/moai-security-encryption

Encryption patterns - AES-GCM, RSA, password hashing, envelope encryption

Open repository

Best 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

Claude CodeCodex CLIGemini CLIOpenCode

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.

```

moai-security-encryption | SkillHub