Symmetric vs. Asymmetric Encryption
Symmetric encryption uses the same key to both encrypt and decrypt data. It's fast, efficient, and ideal for encrypting large amounts of data. The challenge is key distribution — both parties need to share the secret key securely before communicating.
Asymmetric encryption (like RSA) uses a public/private key pair. It solves the key distribution problem but is much slower. In practice, most systems use both: asymmetric encryption to securely exchange a symmetric key, then symmetric encryption for the actual data transfer. This is exactly how HTTPS works.
The AES Algorithm
AES (Advanced Encryption Standard) is the world's most widely used symmetric cipher, standardized by NIST in 2001. It replaced DES and 3DES and is used in virtually every modern security protocol — TLS, disk encryption, VPNs, and more.
AES operates on 128-bit blocks of data (16 bytes at a time) using key sizes of 128, 192, or 256 bits. It applies multiple rounds of substitution, permutation, and mixing transformations.
AES Key Sizes
| Variant | Key Size | Rounds | Security |
|---|---|---|---|
| AES-128 | 128 bits (16 bytes) | 10 | ✅ Secure |
| AES-192 | 192 bits (24 bytes) | 12 | ✅ Secure |
| AES-256 | 256 bits (32 bytes) | 14 | ✅ Recommended |
There's no practical difference in security between AES-128 and AES-256 — both are immune to brute-force attacks with current and foreseeable technology. AES-256 provides a comfortable security margin against quantum computers (which theoretically halve the effective key length through Grover's algorithm).
Block Cipher Modes
A block cipher like AES can only encrypt exactly one 128-bit block at a time. Modes of operation define how to apply a block cipher to arbitrary-length data.
ECB (Electronic Codebook) — Never Use
Each block is encrypted independently. Identical plaintext blocks produce identical ciphertext blocks. This reveals patterns in structured data (the classic example is encrypting an image — shapes remain visible).
CBC (Cipher Block Chaining)
Each block is XORed with the previous ciphertext block before encryption. Requires a random Initialization Vector (IV) for the first block. The IV must be unique per encryption but doesn't need to be secret.
C₀ = IV
Cᵢ = Encrypt(K, Pᵢ ⊕ Cᵢ₋₁)
Good for file encryption. Requires padding to handle non-block-sized data.
GCM (Galois/Counter Mode) — Recommended
Combines counter mode (stream cipher) with a Galois Message Authentication Code (GMAC). Provides authenticated encryption: the output includes an authentication tag that detects any tampering.
AES-256-GCM is the gold standard for symmetric encryption — it's what TLS 1.3 uses for HTTPS.
CTR (Counter Mode)
Encrypts sequential counter values and XORs with plaintext. Can be parallelized and doesn't require padding. No authentication.
Algorithms Comparison
| Algorithm | Status | Key Size | Security |
|---|---|---|---|
| DES | 🔴 Broken | 56 bits | Cracked in 1999 |
| 3DES | 🟡 Deprecated | 112/168 bits | Slow, being retired |
| AES-128 | ✅ Secure | 128 bits | Standard |
| AES-256 | ✅ Recommended | 256 bits | Quantum-resistant margin |
| ChaCha20 | ✅ Modern | 256 bits | Fast on mobile/embedded |
3DES (Triple DES) is used in legacy systems — avoid it for new development. AES has completely superseded it.
Key Derivation from Passwords
When encrypting with a password rather than a random key, you must use a Key Derivation Function (KDF) to transform the password into a proper encryption key. Never use a password directly as an AES key.
// Using PBKDF2 to derive a key from a password
const key = await crypto.subtle.importKey(...);
const derivedKey = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
key, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']
);
Common KDFs: PBKDF2, scrypt, Argon2. Use high iteration counts (100,000+ for PBKDF2) to slow down brute-force attacks.
Practical Encryption Examples
// Web Crypto API (browser)
async function encryptText(plaintext, password) {
const encoder = new TextEncoder();
const data = encoder.encode(plaintext);
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const keyMaterial = await crypto.subtle.importKey(
'raw', encoder.encode(password), 'PBKDF2', false, ['deriveKey']
);
const key = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
keyMaterial, { name: 'AES-GCM', length: 256 }, false, ['encrypt']
);
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data);
return { encrypted, salt, iv };
}
→ Try the Encryption Tool