Symmetric Encryption

Side-channel claim limit. Nothing on this page claims constant-time behaviour or side-channel resistance for any target: the side-channel harness covers nothing (finding A48) and no measurement exists. The Rust and C cores are designed for constant time and unmeasured; managed runtimes (JIT, GC, bounds checks) make no timing claim. Where this page names constant-time or side-channel techniques, in prose or in code, they are design intent or recommendations, not measured properties.

Symmetric encryption algorithms use the same key for both encryption and decryption. MetaMUI provides both block ciphers and stream ciphers with authenticated encryption modes.

Available Algorithms

AES-256

Advanced Encryption Standard

ChaCha20

High-Speed Stream Cipher

ChaCha20-Poly1305

Authenticated Encryption

ARIA-256

Korean Standard Cipher

Camellia-256

Japanese Standard Cipher

Deoxys-II

CAESAR Competition Winner

Algorithm Selection Guide

For New Applications

Recommended: ChaCha20-Poly1305

For Compatibility

Use: AES-256-GCM

For Specific Regions

Usage Examples

Authenticated Encryption (ChaCha20-Poly1305)

from metamui_crypto import ChaCha20Poly1305
import os

# Generate random key
key = os.urandom(32)  # 256 bits

# Create cipher
cipher = ChaCha20Poly1305(key)

# Encrypt with authentication
plaintext = b"Secret message"
nonce = os.urandom(12)  # 96 bits
ciphertext, tag = cipher.encrypt(plaintext, nonce)

# Decrypt and verify
decrypted = cipher.decrypt(ciphertext, tag, nonce)
assert decrypted == plaintext

AES-256-GCM with Associated Data

from metamui_crypto import AES256GCM
import os

# Setup
key = os.urandom(32)
cipher = AES256GCM(key)

# Encrypt with associated data
plaintext = b"Credit card number"
associated_data = b"user_id=12345"
nonce = os.urandom(12)

ciphertext, tag = cipher.encrypt(
    plaintext, 
    nonce,
    associated_data=associated_data
)

# Decrypt (must provide same associated data)
decrypted = cipher.decrypt(
    ciphertext, 
    tag, 
    nonce,
    associated_data=associated_data
)

Stream Encryption (ChaCha20)

from metamui_crypto import ChaCha20
import os

# Setup stream cipher
key = os.urandom(32)
nonce = os.urandom(12)
cipher = ChaCha20(key, nonce)

# Encrypt streaming data
chunk1 = b"First part of data"
chunk2 = b"Second part of data"

encrypted1 = cipher.encrypt(chunk1)
encrypted2 = cipher.encrypt(chunk2)

# Decrypt (must use same key/nonce and order)
decipher = ChaCha20(key, nonce)
decrypted1 = decipher.decrypt(encrypted1)
decrypted2 = decipher.decrypt(encrypted2)

Block Cipher Modes (AES-256)

from metamui_crypto import AES256
import os

key = os.urandom(32)

# ECB mode (not recommended)
cipher_ecb = AES256.new(key, AES256.MODE_ECB)

# CBC mode with IV
iv = os.urandom(16)
cipher_cbc = AES256.new(key, AES256.MODE_CBC, iv)

# CTR mode (converts to stream cipher)
nonce = os.urandom(8)
cipher_ctr = AES256.new(key, AES256.MODE_CTR, nonce=nonce)

# GCM mode (authenticated)
cipher_gcm = AES256.new(key, AES256.MODE_GCM)

Security Considerations

Key Management

Nonce/IV Usage

Authenticated Encryption

Implementation Security

Performance Comparison

Algorithm Encrypt (MB/s) Decrypt (MB/s) Hardware Accelerated
ChaCha20-Poly1305 2,500 2,500 No
AES-256-GCM 3,500* 3,500* Yes
AES-256-CTR 3,800* 3,800* Yes
ARIA-256-GCM 800 800 No
Camellia-256-GCM 900 900 No
Deoxys-II 1,200 1,200 No

*With AES-NI hardware support

Best Practices

1. Choose Authenticated Encryption

# Good: Authenticated encryption
cipher = ChaCha20Poly1305(key)
ciphertext, tag = cipher.encrypt(data, nonce)

# Bad: Encryption without authentication
# cipher = AES256.new(key, AES256.MODE_CBC, iv)
# ciphertext = cipher.encrypt(data)  # No integrity protection!

2. Handle Nonces Properly

import os
from metamui_crypto import ChaCha20Poly1305

# Good: Random nonce for each encryption
def encrypt_message(key, plaintext):
    cipher = ChaCha20Poly1305(key)
    nonce = os.urandom(12)  # Fresh nonce
    ciphertext, tag = cipher.encrypt(plaintext, nonce)
    return nonce + ciphertext + tag  # Include nonce with ciphertext

# Bad: Reusing nonces
# nonce = b'0' * 12  # Never do this!

3. Secure Key Derivation

from metamui_crypto import HKDF, ChaCha20Poly1305
import os

# Derive separate keys for different purposes
master_key = os.urandom(32)
salt = os.urandom(32)

# Derive encryption key
encryption_key = HKDF(
    master_key,
    salt=salt,
    info=b"encryption",
    length=32
)

# Derive MAC key (if needed separately)
mac_key = HKDF(
    master_key,
    salt=salt,
    info=b"mac",
    length=32
)

Migration Guide

From Older Algorithms

# Old: 3DES or Blowfish
# cipher = DES3.new(key, DES3.MODE_CBC, iv)

# New: Modern authenticated encryption
from metamui_crypto import ChaCha20Poly1305
cipher = ChaCha20Poly1305(key)
ciphertext, tag = cipher.encrypt(plaintext, nonce)

From Unauthenticated Modes

# Old: AES-CBC without MAC
# cipher = AES.new(key, AES.MODE_CBC, iv)
# ciphertext = cipher.encrypt(pad(plaintext))

# New: AES-GCM with built-in authentication
from metamui_crypto import AES256GCM
cipher = AES256GCM(key)
ciphertext, tag = cipher.encrypt(plaintext, nonce)

Quantum Resistance

Current symmetric algorithms provide partial quantum resistance:

Algorithm Classical Security Post-Quantum Security
AES-256 256 bits 128 bits
ChaCha20 256 bits 128 bits
ARIA-256 256 bits 128 bits
Camellia-256 256 bits 128 bits

For full post-quantum security, consider:

Resources