Cryptography & PKI Deep Dive
Master applied cryptography: symmetric and asymmetric algorithms, TLS handshake internals, PKI and certificate management, and common crypto implementation attacks like padding oracle and BEAST.
Learning Objectives
- → Understand AES modes of operation and when each is appropriate
- → Explain RSA key generation, encryption, signing, and common weaknesses
- → Trace a complete TLS 1.3 handshake step by step
- → Understand X.509 certificates, CA chains, and OCSP/CRL
- → Identify padding oracle, BEAST, and other crypto implementation attacks
Symmetric Cryptography
Symmetric: same key for encrypt and decrypt
Fast: hardware acceleration (AES-NI instructions)
Problem: key distribution (how to share key securely?)
AES (Advanced Encryption Standard):
- Block cipher: encrypts 128-bit blocks
- Key sizes: 128, 192, 256 bits
- Standard since 2001 (NIST)
- No known practical attacks (brute force: 2^128)
AES Modes of Operation:
ECB (Electronic Code Book):
Each block encrypted independently — identical plaintext = identical ciphertext
NEVER use: reveals patterns (ECB penguin problem)
CBC (Cipher Block Chaining):
XOR each block with previous ciphertext before encryption
Initialization Vector (IV) must be random and unpredictable
Vulnerable to padding oracle if error messages leak padding validity
CTR (Counter Mode):
Encrypts a counter, XOR result with plaintext
Turns block cipher into stream cipher
Parallelizable, no padding needed
GCM (Galois/Counter Mode):
CTR + authentication tag (AEAD)
Provides: confidentiality + integrity + authenticity
PREFERRED: AES-256-GCM for authenticated encryption
Asymmetric Cryptography
RSA
# RSA Key Generation:
# 1. Choose two large primes p and q (2048 bits each)
# 2. n = p * q (modulus, public)
# 3. phi(n) = (p-1)(q-1) (totient)
# 4. e = 65537 (public exponent, public)
# 5. d = e^-1 mod phi(n) (private exponent, secret)
# Public key: (n, e)
# Private key: (n, d)
# Encryption: c = m^e mod n
# Decryption: m = c^d mod n
# Signing: sig = hash(m)^d mod n (private key operation)
# Verify: hash(m) == sig^e mod n (public key operation)
# Common RSA weaknesses:
# 1. Small e with small messages: m^e < n → no modular reduction → just take eth root
# 2. Common modulus: same n for multiple users → shared factor attack
# 3. Textbook RSA: no padding → deterministic encryption, malleable
# 4. Short padding: PKCS#1 v1.5 → Bleichenbacher attack (padding oracle)
# 5. Factoring: n = p*q — if n small enough (<2048 bit), can factor
# factordb.com: database of pre-factored composites for CTF
# RSA in Python:
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
public_key = key.publickey().export_key()
private_key = key.export_key()
Elliptic Curve Cryptography (ECC)
ECC: asymmetric crypto on elliptic curves over finite fields
Much smaller key sizes for equivalent security:
RSA 3072 = ECC 256 (NIST P-256 / secp256k1)
Used in:
- ECDSA: Elliptic Curve Digital Signature Algorithm
- ECDH: Elliptic Curve Diffie-Hellman (key exchange)
- Ed25519: fast, secure digital signatures (SSH, Signal)
ECDH Key Exchange:
Alice: private key 'a', public key A = a*G (G = generator point)
Bob: private key 'b', public key B = b*G
Shared secret: a*B = b*A = a*b*G (same result!)
Eavesdropper sees: A, B — can't compute shared secret without a or b
TLS 1.3 Handshake
TLS 1.3 (RFC 8446) — current standard, deprecates RC4, 3DES, CBC cipher suites
Client → Server: ClientHello
- TLS version: 1.3
- Supported cipher suites: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384
- Supported groups: secp256r1, x25519 (ECDH parameters)
- Key share: client's ECDH public key (start key exchange immediately)
- Random: 32 bytes
- Extensions: SNI (server name), ALPN (http/1.1 or h2)
Server → Client: ServerHello + Certificate + Finished
- Selected cipher suite: TLS_AES_256_GCM_SHA384
- Key share: server's ECDH public key
- Certificate: X.509 cert chain
- Finished: HMAC of all handshake messages (authentication)
Client verifies certificate → derives shared secret → sends Finished
Key derivation (ECDH):
Shared ECDH secret → HKDF → multiple symmetric keys
client_write_key, server_write_key (for encryption)
client_write_iv, server_write_iv (for AES-GCM)
Forward Secrecy (PFS):
Each TLS session uses ephemeral ECDH keys (discarded after session)
Past sessions can't be decrypted even if long-term private key stolen
Required in TLS 1.3 (only ECDHE cipher suites)
X.509 Certificates & PKI
X.509 Certificate fields:
- Version: 3
- Serial Number: unique per CA
- Issuer: CA that signed this cert
- Subject: entity the cert belongs to (CN, O, C)
- Subject Alternative Names (SANs): *.example.com, www.example.com
- Not Before / Not After: validity period
- Public Key: RSA/EC public key
- Extensions: Key Usage, Extended Key Usage
- Signature: CA's digital signature over all fields
Certificate Chain:
Root CA (self-signed, in browser/OS trust store)
└── Intermediate CA (signed by Root CA)
└── Leaf Certificate (signed by Intermediate CA)
Browser trusts Root CA → validates entire chain
Revocation:
CRL (Certificate Revocation List): published list of revoked serials
OCSP (Online Certificate Status Protocol): real-time check
OCSP Stapling: server provides OCSP response in TLS handshake
Transparency:
Certificate Transparency (CT): all CAs must log certs to public logs
Prevents rogue CA issuing certs without domain owner knowledge
Crypto Attack Techniques
Padding Oracle Attack
Affects CBC mode with PKCS#7 padding when server reveals padding validity
PKCS#7 padding:
Need 3 more bytes? Pad with: 0x03 0x03 0x03
Need 0 bytes? Add full block: 0x10 0x10... (16 times)
Padding Oracle: server responds differently to valid vs invalid padding
Valid padding: "Authentication failed"
Invalid padding: 500 Internal Server Error (or different response)
Attack:
For each ciphertext byte: modify it, send to oracle
Observe: valid (200) or invalid (500)
By modifying C[i-1] and checking oracle:
→ Deduce plaintext byte by byte
→ Completely decrypt without the key!
Famous vulnerability: ASP.NET ViewState, POODLE, Lucky 13
Mitigation: use AES-GCM (authenticated encryption) — no padding oracle
Other Classic Attacks
BEAST (Browser Exploit Against SSL/TLS):
TLS 1.0 CBC: predictable IV (chained from last ciphertext block)
Allows chosen-plaintext attack on sessions
Mitigation: TLS 1.2/1.3, RC4 (replaced by better options)
CRIME/BREACH:
Compression + encryption leaks length information
Attacker can deduce CSRF tokens, session cookies from response size
Mitigation: disable HTTP compression for secrets, BREACH mitigations
Sweet32:
64-bit block ciphers (3DES, Blowfish): birthday attack after 2^32 blocks (~32GB)
Mitigation: use AES-256 (128-bit blocks)
Downgrade attacks:
Attacker forces negotiation to older, weaker protocol/cipher
FREAK: force RSA export keys (512-bit, factored in hours)
Logjam: force DHE 512-bit (weak DH groups)
Mitigation: disable old protocol versions, reject weak cipher suites
Timing attacks:
Measure response time to deduce secret information
ECDSA nonce reuse → private key recovery
RSA CRT timing → private key recovery
Mitigation: constant-time implementations
Common Crypto Mistakes
# 1. ECB mode:
from Crypto.Cipher import AES
key = b'0123456789abcdef'
cipher = AES.new(key, AES.MODE_ECB) # BAD
# Identical plaintext blocks = identical ciphertext
# 2. Reused IV:
iv = b'\x00' * 16 # BAD: static IV
cipher = AES.new(key, AES.MODE_CBC, iv)
# Same key + same IV + different data = leaks XOR of plaintexts
# 3. MD5/SHA1 for password hashing:
import hashlib
hashlib.md5(password.encode()).hexdigest() # BAD: reversible with rainbow tables
# GOOD: bcrypt, Argon2, or scrypt:
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
# 4. Home-brew crypto:
def my_encrypt(plaintext, key): # NEVER DO THIS
... # roll your own = always broken
# Use: AES-256-GCM for encryption
from Crypto.Cipher import AES
from os import urandom
key = urandom(32) # GOOD: random key
nonce = urandom(12) # GOOD: random nonce
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
Demonstrate AES ECB weakness and padding oracle: (1) install pycryptodome: pip3 install pycryptodome, (2) encrypt 'AAAAAAAAAAAAAAAA' (32 A's = 2 identical AES blocks) with ECB: both output blocks should be identical, (3) encrypt same with CBC: output blocks are different, (4) simulate a padding oracle: write a function that decrypts ciphertext and returns True/False based on PKCS7 padding validity, (5) implement 1-byte of padding oracle attack manually to decrypt the last byte.
Why is AES-ECB called the 'penguin problem'?
What makes AES-GCM better than AES-CBC for encryption?
Inspect real TLS certificates: (1) openssl s_client -connect google.com:443 -showcerts, (2) examine the certificate chain: Root CA, Intermediate, Leaf, (3) parse the leaf cert: openssl x509 -in cert.pem -text -noout, (4) note: Subject, SAN (Subject Alternative Names), Key usage, Not Before/After, (5) check Certificate Transparency: crt.sh — search for your domain to see all certs ever issued, (6) check OCSP stapling: openssl s_client -connect google.com:443 -status.
What is a wildcard certificate and what is its security limitation?
Classic CTF crypto challenge — ECB cut-and-paste attack: (1) a web app encrypts user profile as ECB: encrypt('[email protected]&uid=10&role=user'), (2) the app then decrypts and parses this as key=value pairs, (3) exploit ECB: craft an email that puts 'admin' padded correctly in its own block, (4) then craft another request where 'role=' is at end of block, (5) combine (cut-and-paste) blocks so 'role=admin' — you can do this because ECB blocks are independent.
Why can ECB blocks be rearranged (cut-and-paste attack)?