Key Takeaways
- Symmetric: Same key encrypts/decrypts (AES)
- Asymmetric: Public/private key pairs (RSA, ECC)
- Hashing: One-way, fixed output (SHA-256)
- Don't roll your own crypto - use libraries
Contents
1. Cryptography Fundamentals
Cryptography provides confidentiality, integrity, authentication, and non-repudiation. It's the foundation of secure communications, authentication, and data protection.
Core Concepts
- Confidentiality: Only intended recipients can read
- Integrity: Data hasn't been modified
- Authentication: Verify identity
- Non-repudiation: Can't deny sending
2. Symmetric Encryption
Same Key for Encrypt/Decrypt
Fast, but key distribution is challenging.
# AES-256-GCM (recommended)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data)
Symmetric Algorithms
- AES: Current standard, 128/192/256-bit keys
- ChaCha20: Modern stream cipher, fast in software
- DES/3DES: Deprecated, don't use
3. Asymmetric Encryption
# RSA key generation
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096
)
public_key = private_key.public_key()
# Encrypt with public key
ciphertext = public_key.encrypt(message, padding.OAEP(...))
# Decrypt with private key
plaintext = private_key.decrypt(ciphertext, padding.OAEP(...))
Asymmetric Algorithms
- RSA: Widely used, 2048-4096 bit keys
- ECC: Smaller keys, same security, faster
- Diffie-Hellman: Key exchange
4. Hash Functions
# One-way functions - can't reverse
import hashlib
# SHA-256 (recommended)
hash = hashlib.sha256(b"message").hexdigest()
# For passwords, use slow hashes
import bcrypt
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))
bcrypt.checkpw(password, hashed)
# Or Argon2 (winner of PHC)
from argon2 import PasswordHasher
ph = PasswordHasher()
hash = ph.hash(password)
5. Digital Signatures
# Sign with private key, verify with public key
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# Sign
signature = private_key.sign(
message,
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
hashes.SHA256()
)
# Verify
public_key.verify(signature, message, padding.PSS(...), hashes.SHA256())
6. PKI & Certificates
# X.509 certificate chain:
# Root CA → Intermediate CA → End-entity certificate
# Generate self-signed certificate (testing only)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
# View certificate
openssl x509 -in cert.pem -text -noout
# Verify certificate chain
openssl verify -CAfile ca-chain.pem certificate.pem
7. TLS/SSL Deep Dive
# TLS 1.3 handshake (simplified):
# 1. ClientHello (supported ciphers, key share)
# 2. ServerHello (chosen cipher, key share, certificate)
# 3. Encrypted communication begins
# Test TLS configuration
testssl.sh https://example.com
# Strong cipher configuration (nginx)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
8. Cryptography Best Practices
- ✅ Use well-tested libraries (OpenSSL, libsodium)
- ✅ AES-256-GCM for symmetric encryption
- ✅ RSA-4096 or ECC P-384 for asymmetric
- ✅ SHA-256 minimum for hashing
- ✅ Argon2id or bcrypt for passwords
- ✅ TLS 1.3 for transport security
- ❌ Never implement your own crypto
- ❌ Never use MD5 or SHA1 for security
- ❌ Never use ECB mode
FAQ
Is AES-256 breakable?
Not with current technology. AES-256 would require 2^256 operations to brute force - more than the atoms in the observable universe.