VOOZH about

URL: https://dev.to/rencberakman/stage-22-cryptography-fundamentals-1eo0

⇱ Stage 2.2 — Cryptography Fundamentals - DEV Community


From Zero to Cybersecurity Professional | Complete Roadmap Series

Series: Cybersecurity × OT/ICS Security — Full Roadmap

Stage: 2 — Cybersecurity Core

Module: 2.2 — Cryptography Fundamentals

Level: Beginner → Advanced

Prerequisites: Stage 2.1 — Core Security Concepts

Next Module: 2.3 — Identity and Access Management


Table of Contents

  1. Why Cryptography Is the Bedrock of All Digital Security
  2. What Is Encryption — First Principles
  3. Encoding vs Encryption vs Hashing
  4. Symmetric Encryption — AES, DES, 3DES, Blowfish
  5. Asymmetric Encryption — RSA, ECC, Diffie-Hellman
  6. Hash Functions — MD5, SHA-1, SHA-256, SHA-3
  7. Salt and Pepper — Password Hashing
  8. Digital Signatures
  9. PKI — Public Key Infrastructure
  10. SSL/TLS — How Secure Connections Work
  11. TLS Handshake — Deep Dive
  12. Cryptographic Randomness
  13. Steganography
  14. Cryptography in OT/ICS Environments
  15. Module Summary

1. Why Cryptography Is the Bedrock of All Digital Security

Every security control that matters depends on cryptography. HTTPS exists because of TLS. Password storage is only safe because of hashing. Code signing, SSH, VPN, MFA apps, email signing, blockchain, digital certificates, secure boot — every one of these is cryptography applied to a specific problem. When cryptography breaks, everything built on it breaks simultaneously.

Concrete failures with massive real-world consequences:

MD5 Collision Attack → Rogue CA Certificate (2008): MD5 was known to be weak, but CAs still used it to sign certificates. Researchers at CWI Amsterdam and others demonstrated that MD5's collision vulnerability could be exploited to create a rogue Certificate Authority certificate indistinguishable from a legitimate one. Any HTTPS connection could be silently intercepted. The entire HTTPS trust system — protecting every bank, government, and healthcare site — was compromised by a 30-year-old hash function that nobody had bothered to replace.

RSA 512-bit factored → FREAK attack (CVE-2015-0204): "Export grade" cryptography mandated by 1990s US government regulations required weak RSA (512-bit) for exports. Attackers could factor 512-bit keys in hours using cloud computing and downgrade victims to export cipher suites. HTTPS connections to affected servers (including major banks and US government websites) could be decrypted.

Heartbleed (CVE-2014-0160): Not a cryptographic break, but a bug in OpenSSL's heartbeat extension that exposed 64KB of server memory per request — including private keys. When a private key is compromised, all past TLS sessions encrypted with that key (if not using Perfect Forward Secrecy) can be decrypted. Every certificate using the compromised key must be revoked and reissued. 17% of all secure web servers were affected simultaneously.

DUHK (Don't Use Hard-coded Keys, 2017): Some VPN implementations used a hardcoded seed value for their random number generator, making it possible to predict all encryption keys. A weak PRNG is as devastating as no encryption — the mathematics are correct, but the key material is predictable.

For OT/ICS: Industrial protocols from the 1980s-2000s (Modbus, DNP3 baseline, PROFIBUS) have no cryptography whatsoever — no authentication, no integrity, no confidentiality. IEC 62351 was developed specifically to add cryptographic security to these protocols, but adoption remains low. Understanding cryptography tells you exactly why a Modbus write command can be forged by anyone on the network and what it would take to prevent it.


2. What Is Encryption — First Principles

2.1 The Core Concept

Encryption transforms readable data (plaintext) into unreadable data (ciphertext) using a mathematical algorithm and a key. Only parties possessing the correct key can reverse the process (decryption) to recover the plaintext.

Encryption:
 Plaintext + Key + Algorithm → Ciphertext
 "Hello" + "K" + AES → "x7Kp2mQ9..."

Decryption:
 Ciphertext + Key + Algorithm → Plaintext
 "x7Kp2mQ9..." + "K" + AES → "Hello"

The algorithm (cipher) is typically PUBLIC — Kerckhoffs's principle:
 "A cryptosystem should be secure even if everything about the
 system, except the key, is public knowledge."

 Rationale: If security depends on algorithm secrecy ("security through
 obscurity"), once the algorithm is discovered (and it will be), all
 security is lost. Security must come from key secrecy alone.

 Corollary: Proprietary/secret encryption algorithms are a red flag.
 They haven't been publicly scrutinised — they are almost certainly weaker
 than publicly reviewed standards like AES.

2.2 The Mathematics of Security

Encryption security is based on mathematical problems that are easy to perform in one direction but computationally infeasible to reverse without the key.

Easy vs Hard Problems in Cryptography:

Symmetric (AES):
 Hard problem: Given ciphertext, find key without the key
 Security: Exhaustive search (brute force) of keyspace
 AES-128: 2^128 possible keys = 3.4 × 10^38 keys
 At 10^18 guesses/second: 1.07 × 10^13 years (longer than universe age)

Asymmetric (RSA):
 Hard problem: Integer Factorisation
 Given N = p × q (product of two large primes), find p and q
 Easy: multiply 2 large primes (milliseconds)
 Hard: factor the product (currently infeasible for 2048-bit)

Asymmetric (ECC):
 Hard problem: Elliptic Curve Discrete Logarithm Problem (ECDLP)
 Given P and Q = k×P (on an elliptic curve), find k
 Currently infeasible for 256-bit curves

 Key insight: 256-bit ECC ≈ 3072-bit RSA in security level
 ECC keys are much shorter for equivalent security

Hash Functions:
 Hard problem: Finding a collision or preimage
 Given H(x), find x (preimage resistance)
 Given H(x), find x' where H(x') = H(x) (second preimage)
 Find any x, x' where H(x) = H(x') (collision resistance)

2.3 Key Length and Security Levels

NIST Recommended Key Sizes (2024):

Security Level Symmetric RSA/DH ECC
──────────────────────────────────────────────────
80-bit 2TDEA 1024 160 (MINIMUM — deprecated)
112-bit 3TDEA 2048 224 (acceptable transitional)
128-bit AES-128 3072 256 (recommended minimum)
192-bit AES-192 7680 384
256-bit AES-256 15360 521

"Security level" = approximate bits of work for best known attack

Future threat — Quantum Computing:
 Shor's algorithm breaks RSA and ECC entirely (exponential speedup)
 Grover's algorithm halves symmetric key security (128-bit → 64-bit effective)

 Post-Quantum Cryptography (PQC) — NIST finalists (2024):
 CRYSTALS-Kyber: Key encapsulation (replaces RSA/ECDH)
 CRYSTALS-Dilithium: Digital signatures (replaces RSA/ECDSA)
 FALCON: Digital signatures
 SPHINCS+: Hash-based signatures (no quantum threat to hash functions)

 Timeline: quantum computers capable of breaking RSA-2048 estimated 10-20 years
 Harvest now, decrypt later: attackers capturing encrypted traffic today
 to decrypt when quantum computers become available
 → "Cryptographically relevant quantum computer" (CRQC) threat

3. Encoding vs Encryption vs Hashing

These three are routinely confused. The confusion has security consequences.

┌─────────────────┬──────────────────────────┬──────────────┬────────────────────┐
│ │ Purpose │ Reversible? │ Key Required? │
├─────────────────┼──────────────────────────┼──────────────┼────────────────────┤
│ ENCODING │ Format conversion │ YES (trivial)│ NO │
│ │ for transmission │ │ │
├─────────────────┼──────────────────────────┼──────────────┼────────────────────┤
│ ENCRYPTION │ Confidentiality │ YES (with key)│ YES │
│ │ (hide data from │ │ │
│ │ unauthorised parties) │ │ │
├─────────────────┼──────────────────────────┼──────────────┼────────────────────┤
│ HASHING │ Integrity verification │ NO │ NO │
│ │ (one-way fingerprint) │ (by design) │ │
└─────────────────┴──────────────────────────┴──────────────┴────────────────────┘

3.1 Encoding

Encoding converts data from one format to another for compatibility or transmission purposes. It provides zero security — it is trivially reversed by anyone.

Common encodings:

Base64:
 Converts binary to printable ASCII
 Used: email attachments (MIME), HTTP Basic Auth, JWT tokens, data URIs
 "Hello" → "SGVsbG8="

 NOT encryption — security implication:
 "Authorization: Basic YWRtaW46cGFzc3dvcmQ=" in HTTP header
 Base64 decode → admin:password (instant)

URL Encoding (Percent Encoding):
 Converts special characters for URL safety
 "Hello World" → "Hello%20World"
 "/" → "%2F"

 Security: URL encoding bypass of WAFs/filters
 /etc/passwd → /%65%74%63/%70%61%73%73%77%64
 Some WAFs decode only once; double-encoded input bypasses them

ASCII/Unicode:
 Character ↔ number mapping
 'A' = 65 = 0x41
 No security provided

Hex encoding:
 Binary → hexadecimal representation
 0x48 0x65 0x6C 0x6C 0x6F = "Hello"

ROT13:
 Caesar cipher (rotate letters 13 positions)
 NOT encryption — symmetric but trivially reversed
 Used as "spoiler protection", never for security
# Encoding demonstrations:

# Base64 encode/decode:
echo "admin:password" | base64 # Encode: YWRtaW46cGFzc3dvcmQ=
echo "YWRtaW46cGFzc3dvcmQ=" | base64 -d # Decode: admin:password

# URL encode/decode with Python:
python3 -c "
import urllib.parse
# Encode
encoded = urllib.parse.quote('/etc/passwd')
print('Encoded:', encoded) # %2Fetc%2Fpasswd

# Double encode (WAF bypass technique)
double = urllib.parse.quote(encoded)
print('Double:', double) # %252Fetc%252Fpasswd
"

# Hex encode/decode:
echo "Hello" | xxd -p # Hex encode: 48656c6c6f0a
echo "48656c6c6f" | xxd -r -p # Hex decode: Hello

# Detect encoding in captured traffic:
echo "SGVsbG8gV29ybGQ=" | base64 -d # Check if it's base64
echo "48656c6c6f" | python3 -c "import sys; print(bytes.fromhex(sys.stdin.read().strip()).decode())"

3.2 The Critical Security Distinction

Most common security mistake: treating encoding as encryption

Example — "stored encoded" passwords (wrong!):
 Password: "SecretPass123"
 Stored as: base64("SecretPass123") = "U2VjcmV0UGFzczEyMw=="
 Security provided: ZERO
 If database is breached: echo "U2VjcmV0UGFzczEyMw==" | base64 -d → SecretPass123

Correct approach:
 Password: "SecretPass123"
 Stored as: bcrypt("SecretPass123") = "$2b$12$LKJSD...."
 Security: computationally infeasible to reverse
 If database is breached: hashes must be cracked (expensive)

Example — "encoded" API credentials in source code:
 API_KEY = base64.encode("ak_prod_12345secret")
 Developers think this hides the key in code
 Anyone who reads the code: decode → plaintext key
 Correct: environment variables, secrets management (Vault, AWS Secrets Manager)

4. Symmetric Encryption — AES, DES, 3DES, Blowfish

4.1 How Symmetric Encryption Works

Symmetric encryption uses the same key for encryption and decryption. The key must be shared between sender and receiver through a secure channel — the "key distribution problem."

Symmetric Encryption Flow:

 Alice Bob
 │ │
 │ Encrypt with shared key K │
 │ "Hello" + K → "x7Kp2mQ9..." │
 │ │
 │ ─── Ciphertext ───────────────→ │
 │ (safe to send publicly) │
 │ │
 │ Decrypt with K │
 │ "x7Kp2mQ9..." + K → "Hello"

Key distribution problem:
 How do Alice and Bob share key K securely?
 If they're communicating for the first time over an insecure channel:
 Sending K over the channel → attacker intercepts K → can decrypt everything

Solution: Use asymmetric encryption to exchange the symmetric key
 (this is exactly what TLS does — see Section 10)

4.2 Block Ciphers vs Stream Ciphers

Block Ciphers:
 Process data in fixed-size blocks (64-bit, 128-bit)
 Examples: AES (128-bit blocks), DES (64-bit blocks)
 Must handle data that isn't exactly block-size → padding
 Mode of operation determines security properties

Stream Ciphers:
 Process data one bit/byte at a time
 Examples: RC4 (broken), ChaCha20 (modern, secure)
 No padding needed
 More efficient for streaming data
 Crucial: NEVER reuse the same key+nonce combination
 Reuse → XOR ciphertexts → plaintext recovered

4.3 Block Cipher Modes of Operation

The mode of operation transforms a block cipher into a complete encryption scheme. Different modes have radically different security properties.

ECB (Electronic Codebook) — NEVER USE:
 Each block encrypted independently with same key
 Same plaintext block → same ciphertext block

 Security failure:
 Block 1: "Hello Wor" → "x7Kp2mQ9"
 Block 2: "Hello Wor" → "x7Kp2mQ9" (IDENTICAL — reveals pattern)

 The Linux Penguin (ECB mode image encryption):
 Encrypt a bitmap image of a penguin with AES-ECB
 The outline of the penguin is still visible in the ciphertext
 Because identical pixel blocks produce identical ciphertext blocks
 ECB is broken for any data with patterns (text, images, structured data)

CBC (Cipher Block Chaining) — Common, requires care:
 Each block XOR'd with previous ciphertext before encryption
 Requires Initialization Vector (IV) for first block
 IV must be random and unique per message

 Vulnerabilities:
 - Padding oracle attacks (POODLE, CBC padding oracle)
 - IV reuse → information leakage
 - CBC decryption is parallelisable, encryption is not

CTR (Counter Mode) — Recommended:
 Uses block cipher as pseudo-random generator
 Counter value encrypted, XOR'd with plaintext
 Transforms block cipher into stream cipher
 Encryption AND decryption are parallelisable
 Random access within ciphertext possible

GCM (Galois/Counter Mode) — Best practice:
 CTR mode + Galois Message Authentication Code (GMAC)
 Provides both confidentiality AND integrity/authentication
 "Authenticated encryption with associated data" (AEAD)

 This is what TLS 1.3 uses: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305

 Critical: GCM nonce must NEVER be reused with the same key
 Nonce reuse in GCM → authentication key revealed → all security lost

4.4 AES — Advanced Encryption Standard

AES (Rijndael algorithm, selected by NIST 2001) is the gold standard for symmetric encryption. Understanding how it works illuminates why it is secure.

AES Specifications:
 Block size: 128 bits (16 bytes) — ALWAYS
 Key sizes: 128, 192, or 256 bits
 Rounds: 10 (AES-128), 12 (AES-192), 14 (AES-256)

AES Internal Structure — Substitution-Permutation Network:

State: 4×4 matrix of bytes (128 bits)
┌──┬──┬──┬──┐
│b0│b4│b8│b12│
│b1│b5│b9│b13│
│b2│b6│b10│b14│
│b3│b7│b11│b15│
└──┴──┴──┴──┘

Each round (except last) applies four operations:

1. SubBytes: each byte replaced by substitute from S-box (256-entry lookup table)
 Provides non-linearity (without this, AES would be linear algebra — trivially broken)

2. ShiftRows: row i is shifted i bytes to the left
 Row 0: unchanged
 Row 1: [b1,b5,b9,b13] → [b5,b9,b13,b1]
 Row 2: [b2,b6,b10,b14] → [b10,b14,b2,b6]
 Row 3: [b3,b7,b11,b15] → [b15,b3,b7,b11]
 Provides diffusion across columns

3. MixColumns: each column multiplied by a matrix in GF(2^8)
 Provides diffusion — one input bit affects multiple output bytes

4. AddRoundKey: XOR state with round key (derived from original key via key schedule)

Final round: SubBytes + ShiftRows + AddRoundKey (no MixColumns)
Key schedule: original key expanded into 11 (AES-128) or 15 (AES-256) round keys

Security: No known attacks significantly better than brute force against AES itself
 All known vulnerabilities are implementation-level (timing attacks, cache attacks)

4.5 DES — Data Encryption Standard

DES (IBM/NIST, 1977) was the dominant encryption standard for 20 years. It is now completely broken.

DES Specifications:
 Block size: 64 bits (8 bytes)
 Key size: 56 bits (actually 64 bits, 8 are parity bits)
 Rounds: 16 (Feistel network)

Why DES is broken:
 56-bit key = 2^56 = 72 quadrillion possible keys
 1998: EFF's "Deep Crack" machine cracked DES in 22 hours for $250,000
 2008: FPGA cluster cracked DES in 6.4 days for $10,000
 2012: Cloud computing: DES crackable in hours for ~$100
 Today: DES cracked in minutes on commodity hardware

DES Attacks:
 - Brute force: 2^56 key search (trivial with modern hardware)
 - Differential cryptanalysis: theoretical attacks requiring 2^47 chosen plaintexts
 - Linear cryptanalysis: requires 2^43 known plaintexts
 - Neither more practical than brute force — brute force is already practical

Do not use DES for any purpose.

4.6 3DES (Triple DES)

3DES applies DES three times to extend effective key length.

3DES Variants:
 DES-EEE3: Encrypt-Encrypt-Encrypt with 3 different keys (168-bit key, 112-bit security)
 DES-EDE3: Encrypt-Decrypt-Encrypt with 3 different keys (most common, "Triple DES")
 DES-EDE2: Encrypt-Decrypt-Encrypt with 2 different keys (K1=K3, 112-bit key, 80-bit security)

Why 3DES doesn't give 168-bit security:
 Meet-in-the-Middle attack reduces DES-EDE3 to ~112 bits of security
 Still exponentially better than single DES

Problems with 3DES:
 - 64-bit block size → "birthday bound" problem
 - After 2^32 blocks (~32 GB), collisions become likely
 - SWEET32 attack (CVE-2016-2183): exploits 64-bit block birthday bound
 to recover plaintext from long-lived TLS sessions using 3DES
 - Only ~112 bits of security (not 168)
 - MUCH slower than AES (3× DES operations per block)

NIST deprecated 3DES in 2017 (allowed until 2023, disallowed after)
3DES is still found in: legacy payment systems (PCI-DSS grace period),
old TLS configurations, mainframe systems

4.7 Blowfish and Twofish

Blowfish (Bruce Schneier, 1993):
 Block size: 64 bits (same birthday-bound problem as DES/3DES)
 Key size: 32-448 bits (variable)
 Design: public domain, no patent

 Security: No known significant vulnerabilities against Blowfish itself
 Problem: 64-bit block size (SWEET32 applies)
 Use: bcrypt password hashing algorithm uses modified Blowfish (Eksblowfish)
 bcrypt is still recommended for passwords — Blowfish-derived, not raw Blowfish

 Do not use raw Blowfish for data encryption today.

Twofish (Schneier et al., 1998):
 AES finalist (lost to Rijndael in 2001 selection)
 Block size: 128 bits (no birthday-bound problem)
 Key size: 128, 192, 256 bits
 Public domain, no patent
 Still considered secure — no known practical attacks
 Less deployed than AES (lost the competition)
 Available in: TrueCrypt/VeraCrypt, GPG, some TLS configurations
# Symmetric encryption in practice:

# AES-256-GCM encryption with OpenSSL:
openssl enc -aes-256-gcm \
 -in plaintext.txt \
 -out encrypted.bin \
 -pass pass:"MySecretPassword" \
 -pbkdf2 \
 -iter 100000
# -aes-256-gcm: AES 256-bit in GCM mode (authenticated encryption)
# -pass pass: derive key from password
# -pbkdf2: use PBKDF2 key derivation (not simple MD5)
# -iter 100000: 100,000 iterations of PBKDF2 (makes brute force slower)

# Decryption:
openssl enc -d -aes-256-gcm \
 -in encrypted.bin \
 -out decrypted.txt \
 -pass pass:"MySecretPassword" \
 -pbkdf2 \
 -iter 100000

# AES in Python (cryptography library):
python3 << 'EOF'
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

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

# Generate random 96-bit nonce (12 bytes — recommended for GCM)
nonce = os.urandom(12)

# Create AES-GCM cipher
aesgcm = AESGCM(key)

# Encrypt
plaintext = b"Secret message"
associated_data = b"authenticated but not encrypted metadata"
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
print(f"Ciphertext: {ciphertext.hex()}")
print(f"Length: {len(ciphertext)} bytes (plaintext + 16-byte auth tag)")

# Decrypt (will raise exception if tampered)
try:
 decrypted = aesgcm.decrypt(nonce, ciphertext, associated_data)
 print(f"Decrypted: {decrypted}")
except Exception as e:
 print(f"Authentication failed: {e}") # Ciphertext was modified
EOF

# Check what cipher a TLS connection uses:
openssl s_client -connect google.com:443 2>/dev/null | grep "Cipher"
# Look for: AES-128-GCM or AES-256-GCM or CHACHA20-POLY1305

# Test if a server still supports broken ciphers:
nmap --script ssl-enum-ciphers -p 443 target.com | grep -E "DES|RC4|NULL|EXPORT"
# Any of these: immediately report — broken ciphers in use

Key Insight: AES-256-GCM is the correct answer for symmetric encryption in 2024. The mode matters as much as the algorithm — AES-ECB is broken regardless of key length. GCM's built-in authentication tag (AEAD) means you get confidentiality and integrity in a single primitive. If you see DES, 3DES, RC4, or ECB mode anywhere in a production system, it is a vulnerability.


5. Asymmetric Encryption — RSA, ECC, Diffie-Hellman

5.1 The Key Exchange Problem — Why Asymmetric Cryptography Exists

Symmetric encryption has a fundamental problem: both parties must share the same key before they can communicate securely. How do you share a key securely with someone you've never met, over an insecure channel?

Asymmetric cryptography (public key cryptography) solves this by using mathematically related key pairs:

  • Public key: can be shared with anyone
  • Private key: kept secret, never shared
Key Pair Relationship:

 Private Key Public Key
 ─────────── ─────────────
 Secret (never share) Share freely
 Decrypts what public Encrypts for private
 key encrypted key holder
 Signs messages Verifies signature

The magic: public and private keys are mathematically related
but it is computationally infeasible to derive the private key
from the public key (assuming the hard problems hold)

Analogy:
 Public key = padlock (anyone can lock)
 Private key = key to open the padlock

 You give your padlock to Alice
 Alice puts message in box, locks with your padlock
 Only you (private key holder) can open the padlock

5.2 RSA — Rivest-Shamir-Adleman

RSA (1977) is based on the difficulty of factoring large integers.

RSA Key Generation:
1. Choose two large prime numbers p and q (each ~1024-2048 bits)
2. Compute n = p × q (the modulus — public)
3. Compute φ(n) = (p-1)(q-1) (Euler's totient — secret)
4. Choose e such that 1 < e < φ(n) and gcd(e, φ(n)) = 1
 (public exponent — usually 65537 = 2^16 + 1)
5. Compute d = e^(-1) mod φ(n) (private exponent)

Public key: (n, e)
Private key: (n, d) [also need p, q for efficient computation]

RSA Encryption (message M):
 Ciphertext C = M^e mod n

RSA Decryption:
 Message M = C^d mod n

Security: Given n, find p and q (integer factorisation)
 This is computationally hard for large n (2048+ bits)

RSA Key Sizes and Security:
 1024-bit: BROKEN (factorable since 2010, do not use)
 2048-bit: Currently secure minimum (recommended for legacy compat)
 3072-bit: Post-2030 recommendation
 4096-bit: High-security applications

RSA Attack History:

RSA-768 factored (2009): 768-bit RSA key factored using 30 years of CPU time
RSA-1024: Not yet factored but academic consensus: should not be used
ROCA vulnerability (CVE-2017-15361):
 Infineon Technologies RSA key generation library flaw
 Generated keys with detectable prime patterns
 Allowed factoring 1024-bit keys in <1 hour, 2048-bit in ~2 weeks
 Affected: YubiKey, TPM chips, smart cards
 1.25 billion keys potentially vulnerable

Bleichenbacher's attack (1998, recurring as ROBOT 2017):
 RSA PKCS#1 v1.5 padding oracle
 If server responds differently to valid vs invalid padding:
 Attacker can recover plaintext of RSA-encrypted messages
 Requires ~1 million queries to server
 Affected F5, Citrix, Cisco, Palo Alto and others in 2017
 ROBOT (Return Of Bleichenbacher's Oracle Threat) - 19 years after original

5.3 ECC — Elliptic Curve Cryptography

ECC is based on the algebraic structure of elliptic curves over finite fields.

Elliptic Curve:
 y² = x³ + ax + b (over a finite field GF(p))

 Standard curves (NIST):
 P-256 (secp256r1): 256-bit, 128-bit security
 P-384 (secp384r1): 384-bit, 192-bit security
 P-521 (secp521r1): 521-bit, 260-bit security

 Alternative curves (more trusted implementation properties):
 Curve25519: Ed25519 signatures, X25519 key exchange (preferred)
 Designed by Daniel Bernstein, no NIST involvement
 No concerns about NIST/NSA backdoor in curve parameters
 Used in: Signal, TLS 1.3 key exchange, SSH keys, WireGuard

ECC Key Exchange (ECDH — Elliptic Curve Diffie-Hellman):
 1. Alice generates private key a, computes public key A = a×G (G = generator point)
 2. Bob generates private key b, computes public key B = b×G
 3. Alice computes shared secret: S = a×B = a×(b×G) = (ab)×G
 4. Bob computes shared secret: S = b×A = b×(a×G) = (ab)×G
 Both get the same shared secret without ever transmitting it

ECC Signatures (ECDSA — Elliptic Curve Digital Signature Algorithm):
 Sign with private key, verify with public key
 Much shorter signatures than RSA for equivalent security:
 RSA-2048 signature: 256 bytes
 ECDSA-256 signature: 64 bytes

Advantage over RSA:
 256-bit ECC ≈ 3072-bit RSA in security
 Shorter keys = faster computation, less storage, smaller certificates
 TLS 1.3 exclusively uses ECDHE for key exchange (no RSA key exchange)

5.4 Diffie-Hellman Key Exchange

DH (1976) was the first public key exchange protocol published. It solves key distribution without ever transmitting the key.

Classic DH (finite field):

1. Public parameters: prime p, generator g (both public, known to everyone)

2. Alice: chooses secret a, computes A = g^a mod p (sends A to Bob)
3. Bob: chooses secret b, computes B = g^b mod p (sends B to Alice)

4. Alice: computes S = B^a mod p = (g^b)^a mod p = g^(ab) mod p
5. Bob: computes S = A^b mod p = (g^a)^b mod p = g^(ab) mod p

Both get the same S = g^(ab) mod p — the shared secret
Attacker sees: p, g, A=g^a mod p, B=g^b mod p
To find S: must solve discrete logarithm problem (find a from g^a mod p)
This is computationally hard for large p

DH Key Sizes:
 1024-bit: deprecated (Logjam attack showed feasibility of precomputation)
 2048-bit: minimum acceptable
 3072-bit: recommended

Ephemeral DH (DHE / ECDHE):
 New a, b generated for each session
 Provides: Perfect Forward Secrecy (PFS)
 If long-term key (private key) is compromised later:
 Past sessions cannot be decrypted (each had unique ephemeral keys)

 CRITICAL SECURITY PROPERTY:
 RSA key exchange (static): compromise private key → decrypt ALL past sessions
 ECDHE: compromise private key → can impersonate server, but past sessions safe

 TLS 1.3 mandates ECDHE — forward secrecy is no longer optional
# Asymmetric cryptography in practice:

# Generate RSA key pair:
openssl genrsa -out private.pem 4096 # Generate 4096-bit RSA private key
openssl rsa -in private.pem -pubout -out public.pem # Extract public key

# View key details:
openssl rsa -in private.pem -text -noout | head -20
# Shows: modulus, public exponent (65537), private exponent, primes

# Generate ECC key pair (preferred):
openssl ecparam -name prime256v1 -genkey -noout -out ec_private.pem # P-256
openssl ec -in ec_private.pem -pubout -out ec_public.pem
# Or use Curve25519 (preferred):
openssl genpkey -algorithm X25519 -out x25519_private.pem
openssl pkey -in x25519_private.pem -pubout -out x25519_public.pem

# RSA encrypt/decrypt:
echo "Secret message" > plaintext.txt
openssl rsautl -encrypt -inkey public.pem -pubin -in plaintext.txt -out encrypted.bin
openssl rsautl -decrypt -inkey private.pem -in encrypted.bin -out decrypted.txt
cat decrypted.txt

# Check a server's public key:
openssl s_client -connect google.com:443 2>/dev/null | \
 openssl x509 -noout -text | grep -E "Public Key Algorithm|Public-Key:"
# Shows: RSA 2048-bit or EC P-256 etc.

# Python - RSA encryption:
python3 << 'EOF'
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization

# Generate 2048-bit RSA key pair
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()

# Encrypt with public key (OAEP padding — correct padding scheme)
message = b"Secret message"
ciphertext = public_key.encrypt(
 message,
 padding.OAEP(
 mgf=padding.MGF1(algorithm=hashes.SHA256()),
 algorithm=hashes.SHA256(),
 label=None
 )
)
print(f"Encrypted: {ciphertext[:20].hex()}... ({len(ciphertext)} bytes)")

# Decrypt with private key
plaintext = private_key.decrypt(
 ciphertext,
 padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
 algorithm=hashes.SHA256(), label=None)
)
print(f"Decrypted: {plaintext}")
EOF

Key Insight: RSA and ECC solve the key distribution problem but are NOT used to encrypt actual data at scale — they are too slow. In practice, asymmetric cryptography is used to securely exchange a symmetric key, which then encrypts the actual data. This hybrid approach (asymmetric for key exchange, symmetric for data encryption) is exactly how TLS works.


6. Hash Functions — MD5, SHA-1, SHA-256, SHA-3

6.1 What Hash Functions Are

A cryptographic hash function takes any input (any size) and produces a fixed-size output (digest/hash) with specific mathematical properties.

Hash Function Properties (required for security):

1. Deterministic: Same input → always same output
 hash("Hello") → always produces the same hash

2. Fixed Output Size: Regardless of input length
 hash("a") → 256 bits
 hash(entire_movie.mp4) → 256 bits (same length)

3. One-Way (Preimage Resistance):
 Given H, computationally infeasible to find M where hash(M) = H
 Cannot reverse the hash to get input

4. Second Preimage Resistance:
 Given M1, computationally infeasible to find M2 where hash(M1) = hash(M2)
 Cannot find a different input with the same hash

5. Collision Resistance:
 Computationally infeasible to find ANY M1, M2 where hash(M1) = hash(M2)
 (Note: collisions MUST exist — infinite inputs, finite outputs)
 But finding them should be computationally infeasible

6. Avalanche Effect: Small change → completely different output
 hash("Hello") → "2cf24d..."
 hash("hello") → "b94d27b9..." (completely different — 1 bit change)
 This prevents any correlation between input and output

6.2 Hash Algorithms Comparison

Algorithm Output Status Best Attack Security
──────────────────────────────────────────────────────────────────────────────
MD5 128-bit BROKEN Collision: 2009 NONE for integrity
 (Flame malware used DO NOT USE
 MD5 collision for
 code signing bypass)
SHA-1 160-bit BROKEN SHAttered (2017): DO NOT USE
 Google/CWI computed for security
 first SHA-1 collision purposes
 Cost: ~$100,000 GPU
SHA-224 224-bit Deprecated Theoretical only Acceptable transitional
SHA-256 256-bit SECURE No practical attack 128-bit security
 known USE THIS
SHA-384 384-bit SECURE No practical attack 192-bit security
SHA-512 512-bit SECURE No practical attack 256-bit security
SHA-3-256 256-bit SECURE Different design 128-bit security
 from SHA-2 family Use for diversity
BLAKE2b 512-bit SECURE No practical attack 256-bit security
 Faster than SHA-3
BLAKE3 256-bit SECURE No practical attack 128-bit security
 Fastest modern hash

6.3 MD5 — Broken

MD5 (Ronald Rivest, 1992):
 Output: 128-bit (32 hex characters)

Timeline of MD5's death:
 1993: Den Boer and Bosselaers: theoretical weaknesses found
 1996: Dobbertin: MD5 compression function collisions found (partial break)
 2004: Wang et al.: first full MD5 collisions computed
 Cost: hours on a laptop
 2005: Lenstra et al.: demonstrated MD5-based X.509 certificate collision
 Two different certificates with the same MD5 hash
 2008: CMU/Sotirov: rogue CA certificate using MD5 collision
 Created fraudulent intermediate CA certificate trusted by all browsers
 Full HTTPS impersonation of any website theoretically possible
 2012: Flame malware: used MD5 collision to forge Microsoft code-signing certificate
 Malware appeared to be legitimately signed by Microsoft
 Affected: Iranian nuclear programme (likely)

MD5 in security today:
 NEVER use for: passwords, digital signatures, certificates, any security purpose
 MAY use for: non-security file deduplication, non-security checksums
 (but SHA-256 is equally fast and secure — just use SHA-256)
 Found in: legacy systems, old configurations, some OT firmware update checks

6.4 SHA-1 — Broken

SHA-1 (NIST, 1995):
 Output: 160-bit (40 hex characters)

Timeline:
 2005: Xiaoyun Wang: theoretical collision attack (2^69 operations vs 2^80 ideal)
 2007: NIST recommends migration away from SHA-1
 2011: CA/Browser Forum: ban SHA-1 certificates after 2015
 2017: SHAttered attack (Google/CWI Amsterdam):
 First SHA-1 collision computed
 Two different PDF files with IDENTICAL SHA-1 hashes
 Cost: 9 quintillion SHA-1 computations = ~$100,000 in cloud computing
 Same PDF files have different content but same SHA-1 hash

 2020: Chosen-prefix collision: find collision given arbitrary prefixes
 More powerful than identical-prefix collision
 Cost reduced to ~$50,000

Impact of SHAttered:
 Git uses SHA-1 internally (aware, mitigations added: SHA-256 migration ongoing)
 Any SHA-1-based integrity check can potentially be bypassed

SHA-1 in security today:
 NEVER use for: digital signatures, certificates, TLS, code signing
 Legacy OT concern: many industrial firmware update mechanisms use SHA-1
 for integrity verification — still vulnerable to SHAttered
 type attacks on controlled devices

6.5 SHA-256 and SHA-3

SHA-256 (NIST, 2001) — Part of SHA-2 family:
 Output: 256-bit (64 hex characters)
 Internal structure: Merkle-Damgård construction with Davies-Meyer compression
 No practical attacks known
 Used in: Bitcoin, TLS, code signing, most modern security applications

SHA-3 (Keccak, NIST standardised 2015):
 Different internal structure from SHA-2 (sponge construction)
 Not vulnerable to length extension attacks (SHA-2 is)
 SHA-3-256 output: 256-bit
 Adoption: slower (SHA-2 still dominant)
 Use case: when diversity from SHA-2 is needed (defence against future SHA-2 attacks)

Length Extension Attack (SHA-2 weakness, not SHA-3):
 Given H(m) and len(m) but NOT m:
 Attacker can compute H(m || padding || extension) without knowing m

 Attack scenario:
 API: sign request with SHA-256(secret_key || request_params)
 Attacker: knows H(secret_key || "user=alice")
 Can compute H(secret_key || "user=alice" || padding || "&admin=true")
 Without knowing secret_key!

 Fix: use HMAC instead of raw hash for message authentication
 HMAC is not vulnerable to length extension attacks
# Hash function demonstrations:

# Calculate hashes of same file:
echo "Hello World" > test.txt
md5sum test.txt # MD5: e59ff97941044f85df5297e1c302d260
sha1sum test.txt # SHA1: 648a6a6ffffdaa0badb23b8baf90b6168dd16b3a
sha256sum test.txt # SHA256: d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26
sha512sum test.txt # SHA512: (128 hex chars)
b2sum test.txt # BLAKE2b (package: b2sum)

# Verify file integrity (download verification):
wget https://example.com/software.tar.gz
wget https://example.com/software.tar.gz.sha256sum
sha256sum -c software.tar.gz.sha256sum
# "software.tar.gz: OK" = file not tampered

# Demonstrate avalanche effect:
python3 << 'EOF'
import hashlib

msg1 = b"Hello World"
msg2 = b"Hello world" # Only capital W changed

h1 = hashlib.sha256(msg1).hexdigest()
h2 = hashlib.sha256(msg2).hexdigest()

print(f"SHA-256('Hello World'): {h1}")
print(f"SHA-256('Hello world'): {h2}")

# Count differing bits:
b1 = int(h1, 16)
b2 = int(h2, 16)
diff = bin(b1 ^ b2).count('1')
print(f"Differing bits: {diff} out of 256 ({diff/256*100:.1f}%)")
# Approximately 128 bits differ (50%) — avalanche effect
EOF

# Demonstrate MD5 collision (SHAttered file pair):
# Download the two PDF files that have same SHA-1:
# wget https://shattered.io/static/shattered-1.pdf
# wget https://shattered.io/static/shattered-2.pdf
# sha1sum shattered-1.pdf shattered-2.pdf # IDENTICAL SHA-1
# sha256sum shattered-1.pdf shattered-2.pdf # DIFFERENT SHA-256

# HMAC (keyed hash, MAC):
python3 -c "
import hmac, hashlib
key = b'secret_key'
message = b'user=alice&action=transfer&amount=1000'
mac = hmac.new(key, message, hashlib.sha256).hexdigest()
print(f'HMAC-SHA256: {mac}')
# Attacker cannot forge this without knowing the key
# Not vulnerable to length extension attacks
"

7. Salt and Pepper — Password Hashing

7.1 Why Naive Password Hashing Fails

Simply hashing passwords and storing the hash is insufficient protection. Two attacks defeat it:

Attack 1 — Rainbow Tables:
 Precompute hashes of millions of common passwords:
 MD5("password") = "5f4dcc3b5aa765d61d8327deb882cf99"
 MD5("123456") = "e10adc3949ba59abbe56e057f20f883e"
 MD5("admin") = "21232f297a57a5a743894a0e4a801fc3"

 Breach database → look up hash in precomputed table → plaintext in milliseconds
 No computation needed — just lookup

 Countermeasure: Salt (makes precomputation impossible)

Attack 2 — Dictionary Attack:
 Hash common passwords and compare to stolen hashes
 For each candidate password: compute hash → compare
 GPU can compute billions of SHA-256 hashes per second

 Countermeasure: Slow hash functions (bcrypt, scrypt, Argon2)

7.2 Salt

A salt is a random value unique to each password, added before hashing.

WITHOUT SALT:
 User A: password "letmein" → SHA-256 → "b3fba..."
 User B: password "letmein" → SHA-256 → "b3fba..."

 Same password → same hash
 Attacker sees: User A and B have same hash → same password
 Crack one → crack both
 Rainbow table works: "b3fba..." → "letmein"

WITH SALT:
 User A: password "letmein" + salt "xK7mP2" → SHA-256 → "a1b2c3..."
 User B: password "letmein" + salt "9qRnL5" → SHA-256 → "z9y8x7..."

 Same password → DIFFERENT hashes (different salts)
 Attacker must crack each hash independently
 Rainbow tables are useless (different salt = different table needed per user)

 Salt must be:
 - Random (generated with CSPRNG)
 - Unique per password (even same user resetting password gets new salt)
 - Stored alongside the hash (not secret — attacker who gets DB gets salt too)
 But that's OK — salt defeats rainbow tables even when known
 - Long enough: 16+ bytes (128+ bits)

bcrypt (Blowfish-based, 1999):
 Incorporates salt automatically
 Output format: $2b$12$SALT22CHARS.HASH31CHARS
 $2b$ = bcrypt version
 12 = cost factor (2^12 rounds = 4096 iterations)
 next 22 chars = salt (128 bits)
 last 31 chars = hash

 Cost factor: controls speed (and therefore brute-force resistance)
 Higher cost = slower hash = more resistant to brute force
 Recommendation: choose cost factor so hashing takes 100-300ms
 Increase cost factor over time as hardware gets faster

Argon2 (Password Hashing Competition winner, 2015):
 Three variants:
 Argon2d: data-dependent, resists GPU cracking
 Argon2i: data-independent, resists side-channel attacks
 Argon2id: hybrid, RECOMMENDED for passwords

 Parameters: time cost, memory cost, parallelism
 Memory cost: makes hardware attacks (ASIC/GPU) expensive
 Argon2id(time=3, memory=64MB, parallel=4) recommended by OWASP (2024)

7.3 Pepper

A pepper is an additional secret value added to passwords before hashing, stored separately from the database (in application code, HSM, or configuration).

WITH SALT + PEPPER:
 password + salt + pepper → hash

 Storage:
 Database: salt + hash (attacker who breaches DB gets these)
 Application/HSM: pepper (attacker who only breaches DB doesn't have this)

 Even with: stolen database + knowing salt + knowing algorithm
 Attacker cannot crack without pepper
 Must also breach application server or HSM

 Pepper requirements:
 - HIGH entropy (256 bits random)
 - Different from the salt
 - Stored separately from the database (application config, HSM)
 - Never logged or exposed in error messages
 - Rotate with re-hashing (requires all users to re-authenticate)

Limitations:
 If attacker compromises BOTH database AND application server: both salt and pepper available
 Pepper is only effective if the attacker has access to ONE but not both

Combined: salt + pepper + slow hash (Argon2id or bcrypt) is the current gold standard
# Password hashing in practice:

# bcrypt in Python:
python3 << 'EOF'
import bcrypt
import time

password = b"UserPassword123!"
pepper = b"AppSecretPepper256BitRandom" # Store in app config, not DB

# Hash (bcrypt handles salt automatically)
peppered = password + pepper
start = time.time()
hashed = bcrypt.hashpw(peppered, bcrypt.gensalt(rounds=12))
elapsed = time.time() - start
print(f"bcrypt hash: {hashed.decode()}")
print(f"Time to hash: {elapsed:.3f}s (should be ~100-300ms)")

# Verify:
is_valid = bcrypt.checkpw(peppered, hashed)
print(f"Password valid: {is_valid}")

# Wrong password:
wrong = b"WrongPassword" + pepper
is_valid = bcrypt.checkpw(wrong, hashed)
print(f"Wrong password valid: {is_valid}") # False
EOF

# Argon2id in Python:
python3 << 'EOF'
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

# OWASP recommended parameters
ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4, hash_len=32, salt_len=16)
# time_cost=3: 3 iterations
# memory_cost=65536: 64MB RAM (makes GPU/ASIC attacks expensive)
# parallelism=4: use 4 threads

password = "UserPassword123!"
pepper = "AppSecretPepper"

hash_val = ph.hash(password + pepper)
print(f"Argon2id hash: {hash_val[:50]}...")

# Verify:
try:
 ph.verify(hash_val, password + pepper)
 print("Password valid")
except VerifyMismatchError:
 print("Password invalid")
EOF

# Check what hash algorithm is used in /etc/shadow:
sudo cat /etc/shadow | head -3 | cut -d: -f2 | cut -c1-5
# $6$ = SHA-512 (acceptable for system use)
# $5$ = SHA-256
# $y$ = yescrypt (best, modern Linux default)
# $2b$ = bcrypt
# Blank or no $ = no password (check immediately!)

# Crack example hashes to understand speed difference:
# hashcat -m 0 hash.txt wordlist.txt # MD5: billions/sec
# hashcat -m 3200 hash.txt wordlist.txt # bcrypt: thousands/sec
# hashcat -m 1800 hash.txt wordlist.txt # SHA-512crypt: millions/sec
# Speed difference: MD5 = 1,000,000× faster than bcrypt
# This is exactly why bcrypt for passwords matters

Key Insight: Password storage security is not about using "a hash" — it is about using a purpose-built, slow password hashing function (Argon2id or bcrypt) with a random unique salt. SHA-256(password) is not password storage — it is broken password storage. The goal is to make brute forcing so slow that even a database breach yields no crackable passwords within an attacker's operational window.


8. Digital Signatures

8.1 What Digital Signatures Provide

A digital signature provides three guarantees simultaneously:

  • Authentication: The message came from the claimed sender (they have the private key)
  • Integrity: The message has not been modified since signing
  • Non-repudiation: The sender cannot deny having sent it (only they have the private key)
Digital Signature Process:

SIGNING (sender with private key):
 Message M → Hash(M) → Sign with Private Key → Signature S
 Send: (M, S)

VERIFICATION (receiver with public key):
 Receive: (M, S)
 Compute: Hash(M) → H1
 Decrypt: S with Public Key → H2
 Verify: H1 == H2?
 YES: signature valid (M not tampered, came from key holder)
 NO: signature invalid (M modified, or wrong signer)

Why hash first?
 RSA can only sign data ≤ key size (2048 bits)
 Hash reduces any-size message to fixed output (256 bits for SHA-256)
 Sign the hash, not the message

 RSA-PSS (Probabilistic Signature Scheme) — correct:
 Uses random salt, provably secure, RECOMMENDED

 RSA-PKCS1v15 — legacy:
 Deterministic, older vulnerabilities, still widely used but avoid for new systems

 ECDSA (Elliptic Curve Digital Signature Algorithm):
 Based on ECC discrete log problem
 256-bit signature (much shorter than RSA-2048's 256-byte signature)
 Requires cryptographically random k value per signature

 Critical ECDSA vulnerability: k reuse
 If same k used twice with different messages:
 Private key can be recovered algebraically

 2010: PlayStation 3 used constant k in ECDSA → private key recovered
 2013: Android Bitcoin wallet ECDSA k reuse → keys stolen

8.2 Code Signing

Code Signing: applying digital signatures to software to verify authenticity

Windows Authenticode:
 Developer signs executable with private key (from certificate authority)
 Windows verifies signature before execution (if policy enforced)
 "Published by: Microsoft Corporation" with valid chain → trusted
 Self-signed → warning
 No signature → warning or block

 Attack: steal code signing certificate and private key
 Example: Stuxnet used stolen certificates from Realtek and JMicron
 to sign kernel drivers → bypassed Windows driver signing requirement

Linux Package Signing:
 Debian/Ubuntu: GPG signatures on packages + repository metadata
 RPM: GPG signatures on packages
 apt: verifies package signatures automatically

 Verify GPG signature:
 gpg --verify file.sig file

Certificate Transparency (CT):
 All publicly trusted TLS certificates must be logged to CT logs
 Allows monitoring for unexpected certificates for your domains
 Tools: crt.sh, certspotter, Google CT

SSH Host Key Verification:
 SSH server presents public key fingerprint
 Client verifies against known_hosts
 First connection: TOFU (Trust On First Use) — user must verify
# Digital signatures in practice:

# Sign a file with private key:
openssl dgst -sha256 -sign private.pem -out signature.bin document.txt

# Verify signature:
openssl dgst -sha256 -verify public.pem -signature signature.bin document.txt
# "Verified OK" = authentic and unmodified

# Sign with GPG:
gpg --gen-key # Generate GPG key pair
gpg --sign --armor document.txt # Sign (creates document.txt.asc)
gpg --verify document.txt.asc document.txt # Verify signature

# Python - sign and verify:
python3 << 'EOF'
from cryptography.hazmat.primitives.asymmetric import ec, utils
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.exceptions import InvalidSignature

# Generate EC key pair (P-256)
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()

# Sign message
message = b"This document is authentic"
signature = private_key.sign(message, ec.ECDSA(hashes.SHA256()))
print(f"Signature: {signature.hex()[:40]}... ({len(signature)} bytes)")

# Verify - original message:
try:
 public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
 print("Signature VALID")
except InvalidSignature:
 print("Signature INVALID")

# Verify - tampered message:
tampered = b"This document is authentic and has extra admin=true"
try:
 public_key.verify(signature, tampered, ec.ECDSA(hashes.SHA256()))
 print("Tampered signature VALID") # Should never reach here
except InvalidSignature:
 print("Tampered message: Signature INVALID — tampering detected!")
EOF

# Check certificate signature:
openssl s_client -connect google.com:443 2>/dev/null | \
 openssl x509 -noout -text | grep -A3 "Signature Algorithm"

9. PKI — Public Key Infrastructure

9.1 The Problem PKI Solves

Asymmetric cryptography lets us encrypt to anyone with their public key. But how do you know that the public key claiming to be "google.com" actually belongs to Google and not an attacker?

PKI (Public Key Infrastructure) is the system of trust, policies, procedures, and technologies that manages digital certificates, binding public keys to verified identities.

The Man-in-the-Middle Problem:

Without PKI:
 Alice wants to connect to "bank.com"
 Attacker intercepts connection:
 Alice ←→ Attacker ←→ Bank
 Attacker sends own public key to Alice, claiming to be Bank
 Alice encrypts with attacker's key
 Attacker decrypts, re-encrypts with bank's real key
 Alice has no way to know she's talking to the attacker

With PKI:
 Bank has a certificate signed by a trusted Certificate Authority (CA)
 Certificate contains: Bank's public key + domain name + CA signature
 Alice's browser trusts the CA (comes pre-installed)
 Browser verifies: CA signature is valid → this public key belongs to bank.com
 Attacker cannot forge this — doesn't have CA's private key

9.2 Certificate Structure (X.509)

X.509 Certificate Fields:

Version: 3 (v3 is current)
Serial Number: Unique identifier assigned by CA
Signature Algorithm: sha256WithRSAEncryption or ecdsa-with-SHA256
Issuer: CA that signed this certificate
 CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1
Validity:
 Not Before: 2024-01-01 00:00:00 UTC
 Not After: 2025-01-31 23:59:59 UTC
Subject: Who this certificate belongs to
 CN=*.google.com, O=Google LLC, C=US
Subject Public Key: The actual public key (RSA or EC)
 RSA 2048-bit or ECC P-256
Extensions:
 Subject Alternative Names (SANs): All domains covered
 DNS:*.google.com
 DNS:google.com
 Key Usage: Digital Signature, Key Encipherment
 Extended Key Usage: TLS Web Server Authentication
 Certificate Policies: https://pki.goog/repository/
 CRL Distribution Points: URL to check if certificate is revoked
 OCSP: URL for real-time revocation checking
 Certificate Transparency: SCT list (proof of CT log inclusion)
Signature: CA's signature over all of the above

9.3 Certificate Chain of Trust

PKI Trust Hierarchy:

Root CA (self-signed, highest trust)
 └── Intermediate CA (signed by Root CA)
 └── End-Entity Certificate (signed by Intermediate CA)
 (the certificate for google.com, for example)

Root CA:
 Stored in OS/browser trust stores (pre-installed)
 ~150 trusted root CAs in major browsers
 Private key extremely protected (offline, HSM, physical vault)
 Very rarely used directly (too valuable to risk)

Intermediate CA:
 Signed by root CA, issues end-entity certificates
 Private key stored in HSM (Hardware Security Module)
 If compromised: can be revoked without compromising root

End-Entity Certificate:
 Issued to the specific organisation/domain
 Short-lived (1 year max since 2020 for public TLS)

Chain validation:
 Browser validates end-entity cert is signed by intermediate CA
 Validates intermediate CA is signed by root CA
 Validates root CA is in trusted store
 Validates none are expired or revoked
 Validates domain name matches (SAN check)

9.4 Certificate Revocation

What if a private key is compromised? Certificate must be revoked.

CRL (Certificate Revocation List):
 List of revoked serial numbers, signed by CA, published periodically
 Browsers download CRL and check if certificate serial number is in it
 Problem: CRL can be large, infrequent updates, check often skipped

OCSP (Online Certificate Status Protocol):
 Real-time revocation check — query CA's OCSP responder per certificate
 Faster than CRL, smaller response
 Problem: Privacy (CA knows which sites you visit), performance, failure mode

OCSP Stapling:
 Server periodically fetches its own OCSP response from CA
 Includes ("staples") the response in TLS handshake
 Browser gets revocation status without contacting CA
 Best approach: solves privacy and performance

Revocation in practice (sadly):
 Browser failure to get CRL/OCSP response → typically ALLOW connection
 "Soft fail" = revocation checking provides minimal real protection
 Exception: Certificate Pinning — browser refuses connection if pin mismatch

CAA DNS Records:
 DNS record specifying which CAs may issue certificates for your domain
 example.com CAA 0 issue "letsencrypt.org"
 Prevents misissued certificates from unauthorised CAs
 Check: dig CAA yourdomain.com
# PKI and certificate analysis:

# View a server's full certificate chain:
openssl s_client -connect google.com:443 -showcerts 2>/dev/null | \
 grep -E "BEGIN|END|subject|issuer|Not"

# Check certificate details:
openssl s_client -connect google.com:443 2>/dev/null | \
 openssl x509 -noout -text | grep -E "Subject:|Issuer:|Not After|DNS:"

# Verify certificate chain:
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt certificate.pem

# Check OCSP status:
openssl s_client -connect google.com:443 -status 2>/dev/null | grep -A5 "OCSP"

# Check if certificate is about to expire (monitoring):
openssl s_client -connect target.com:443 2>/dev/null | \
 openssl x509 -noout -enddate | \
 awk -F= '{print $2}' | \
 xargs -I{} date -d "{}" +%s | \
 awk -v now=$(date +%s) '{days=($1-now)/86400; print "Expires in " int(days) " days"}'

# Monitor certificate changes (detect unexpected reissue):
openssl s_client -connect target.com:443 2>/dev/null | \
 openssl x509 -fingerprint -sha256 -noout
# Compare fingerprint over time — unexpected change = possible attack or cert rotation

# Certificate transparency monitoring (your domain):
curl -s "https://crt.sh/?q=yourdomain.com&output=json" | \
 python3 -c "
import json,sys
certs = json.load(sys.stdin)
for c in certs[:10]:
 print(c['not_before'][:10], c['name_value'], c['issuer_name'][:50])
"
# Review for unexpected certificates issued for your domain

# Generate self-signed certificate (for testing/internal use only):
openssl req -x509 -newkey rsa:4096 \
 -keyout private.pem \
 -out certificate.pem \
 -days 365 \
 -subj "/CN=localhost/O=Test/C=US" \
 -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

10. SSL/TLS — How Secure Connections Work

10.1 SSL to TLS Evolution

Timeline:
 SSL 1.0 (Netscape, 1994): Never released (serious flaws found)
 SSL 2.0 (1995): Released, flaws found quickly
 SSL 3.0 (1996): Still broken (POODLE 2014 — CVE-2014-3566)
 TLS 1.0 (1999): RFC 2246, BEAST vulnerability (CVE-2011-3389)
 TLS 1.1 (2006): Fixed BEAST, still has issues
 TLS 1.2 (2008): Current acceptable standard
 TLS 1.3 (2018): Current best practice, significant redesign

Deprecated (should not be used):
 SSL 2.0, SSL 3.0: COMPLETELY BROKEN, disable everywhere
 TLS 1.0, TLS 1.1: Deprecated by RFC 8996 (2021)
 Chrome/Firefox removed support 2020

 Current standard: TLS 1.2 minimum, TLS 1.3 preferred

10.2 What TLS Provides

TLS provides a secure channel with three properties:

1. Confidentiality: All application data encrypted
 (Before TLS: plaintext visible to any network observer)

2. Integrity: Data cannot be modified without detection
 (HMAC or AEAD authentication tags detect any tampering)

3. Authentication: Server (and optionally client) identity verified
 (Via certificate chain validation)

What TLS does NOT protect:
 - Metadata: IP addresses, TCP ports, timing, volume
 - Server-side application vulnerabilities
 - The DNS lookup that led to the connection
 - Traffic analysis (size and timing patterns)
 - Certificate validity (user must check/browser must validate)

TLS components:
 Record Protocol: Fragments, compresses (deprecated), encrypts, MACs application data
 Handshake Protocol: Negotiates cipher suite, authenticates server, establishes keys
 Alert Protocol: Signals errors and close notifications
 Change Cipher Spec: Signals switch to negotiated cipher (TLS 1.2 only)

10.3 TLS Cipher Suites

TLS 1.2 Cipher Suite naming (verbose):
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

 TLS: Protocol
 ECDHE: Key Exchange (Elliptic Curve Diffie-Hellman Ephemeral — forward secrecy)
 RSA: Authentication (certificate type — RSA cert verifies server identity)
 WITH: Separator
 AES_256_GCM: Symmetric cipher (AES 256-bit in GCM mode)
 SHA384: HMAC algorithm for integrity (for PRF function in TLS 1.2)

Components:
 Key Exchange: ECDHE > DHE > RSA (RSA key exchange has no forward secrecy — avoid)
 Auth: ECDSA > RSA (for certificates)
 Cipher: AES-GCM > AES-CBC (GCM is authenticated, CBC requires separate MAC)
 PRF/HMAC: SHA-384 > SHA-256 > MD5/SHA-1 (avoid weak hashes)

TLS 1.3 cipher suites (simplified, only 5 allowed):
 TLS_AES_128_GCM_SHA256 (default, fast)
 TLS_AES_256_GCM_SHA384 (high security)
 TLS_CHACHA20_POLY1305_SHA256 (mobile/embedded — faster without AES-NI)
 TLS_AES_128_CCM_SHA256 (constrained environments)
 TLS_AES_128_CCM_8_SHA256 (very constrained IoT)

 Note: TLS 1.3 separates authentication (certificate) from key exchange
 No more RSA key exchange — only ECDHE or DHE
 All TLS 1.3 cipher suites have forward secrecy by default

Weak cipher suites to detect and disable:
 *_NULL_*: No encryption (plaintext)
 *_EXPORT_*: 40/56-bit keys (FREAK/Logjam attack)
 *_RC4_*: RC4 stream cipher (broken since 2013)
 *_DES_*: 56-bit DES (trivially cracked)
 *_3DES_*: 112-bit 3DES (SWEET32, slow)
 *_MD5: MD5 MAC (broken)
 *_SHA: SHA-1 MAC (weakened)
 *RSA_WITH_*: RSA key exchange (no forward secrecy)
 *_ANON_*: Anonymous (no authentication — trivial MITM)

11. TLS Handshake — Deep Dive

11.1 TLS 1.2 Handshake

TLS 1.2 Full Handshake:

Client Server
 │ │
 │──── ClientHello ───────────────────────────→ │
 │ Version: TLS 1.2 │
 │ Random: 32 bytes (includes timestamp) │
 │ Session ID: (for resumption) │
 │ Cipher Suites: [list of supported] │
 │ Extensions: SNI, ALPN, elliptic curves... │
 │ │
 │ ←── ServerHello ─────────────────────────── │
 │ Version: TLS 1.2 │
 │ Random: 32 bytes │
 │ Session ID: (new or resumed) │
 │ Cipher Suite: SELECTED ONE │
 │ │
 │ ←── Certificate ─────────────────────────── │
 │ Server's X.509 certificate(s) │
 │ [Full chain: end-entity + intermediates] │
 │ │
 │ ←── ServerKeyExchange (if ECDHE/DHE) ───── │
 │ DH parameters + server's DH public value │
 │ Signed with server's private key │
 │ │
 │ ←── ServerHelloDone ─────────────────────── │
 │ │
 │ Client validates: │
 │ Certificate chain → trusted CA │
 │ Server hostname matches SAN │
 │ Not expired, not revoked │
 │ ServerKeyExchange signature valid │
 │ │
 │──── ClientKeyExchange ──────────────────────→ │
 │ Client's DH public value │
 │ │
 │ [Both compute: Pre-Master Secret from DH] │
 │ [Both derive: Master Secret] │
 │ [Both derive: 4 session keys from MS] │
 │ client_write_key, server_write_key │
 │ client_write_MAC, server_write_MAC │
 │ │
 │──── ChangeCipherSpec ───────────────────────→ │
 │ "I'll now use the negotiated cipher" │
 │ │
 │──── Finished (encrypted) ───────────────────→ │
 │ HMAC of entire handshake transcript │
 │ Verifies nothing was tampered during setup │
 │ │
 │ ←── ChangeCipherSpec ─────────────────────── │
 │ ←── Finished (encrypted) ─────────────────── │
 │ │
 │ ════════ Application Data (encrypted) ═══════ │

Total round trips: 2-RTT (2 full round trips before data flows)
This latency matters — TLS 1.3 reduces to 1-RTT

11.2 TLS 1.3 Handshake

TLS 1.3 Handshake — Redesigned for speed and security:

Client Server
 │ │
 │──── ClientHello ───────────────────────────→ │
 │ Version: TLS 1.3 │
 │ Random: 32 bytes │
 │ Cipher Suites: [TLS 1.3 only suites] │
 │ key_share: Client's ECDH public key │
 │ (Client guesses server's preferred group) │
 │ supported_versions: [TLS 1.3, TLS 1.2...] │
 │ pre_shared_key: (for 0-RTT resumption) │
 │ │
 │ [Server can now compute handshake key] │
 │ [Server begins encrypting immediately] │
 │ │
 │ ←── ServerHello ─────────────────────────── │
 │ Version: TLS 1.3 │
 │ key_share: Server's ECDH public key │
 │ (Both now compute shared secret) │
 │ │
 │ ←── {Certificate} ────────────────────────── │ ← Encrypted!
 │ ←── {CertificateVerify} ──────────────────── │ ← Encrypted!
 │ Signature over entire handshake transcript │
 │ ←── {Finished} ────────────────────────────── │ ← Encrypted!
 │ │
 │ Client validates certificate (encrypted) │
 │ │
 │──── {Finished} ─────────────────────────────→ │
 │ │
 │ ════════ Application Data (encrypted) ═══════ │

Key improvements in TLS 1.3:
 1-RTT: Faster by one full round trip (vs TLS 1.2's 2-RTT)
 0-RTT: Session resumption can send data in the first message
 (Security tradeoff: 0-RTT data not forward secret, replay risk)

 No more:
 RSA key exchange (eliminated — only ECDHE/DHE)
 CBC cipher suites (GCM and ChaCha20 only)
 MD5, SHA-1 in MAC (SHA-256 minimum)
 DH with <2048-bit primes
 Export cipher suites
 Session renegotiation (was a security issue in TLS 1.2)
 Compression (CRIME attack)

 Certificate and CertificateVerify now encrypted:
 In TLS 1.2, certificate was sent in plaintext → server identity visible to observer
 In TLS 1.3, certificate encrypted → privacy improvement

 Encrypted ClientHello (ECH) — draft standard:
 Extends encryption to ClientHello (SNI currently plaintext)
 When standardised: server hostname hidden from observer

11.3 TLS Attack Landscape

BEAST (CVE-2011-3389):
 Target: TLS 1.0 CBC mode
 Method: Chosen-boundary attack against CBC's predictable IV
 Impact: Decrypt HTTPS session cookies
 Fix: Use TLS 1.2+ (fixed IV handling), use RC4 (now broken too), AES-GCM

CRIME (CVE-2012-4929):
 Target: TLS compression (DEFLATE)
 Method: Compression oracle — inject guesses, observe size change
 Impact: Recover HTTPS cookies
 Fix: Disable TLS compression (disabled by default in all modern implementations)

POODLE (CVE-2014-3566):
 Target: SSL 3.0 CBC mode
 Method: Padding oracle after downgrade to SSL 3.0
 Impact: Decrypt session cookies
 Fix: Disable SSL 3.0 entirely, use TLS 1.2+

Heartbleed (CVE-2014-0160):
 Target: OpenSSL heartbeat extension (TLS extension)
 Method: Missing bounds check — request more data than sent
 Impact: Up to 64KB of server memory per request
 Exposed: private keys, session tickets, passwords, other secrets
 Fix: Patch OpenSSL (1.0.1g), reissue all certificates, rotate secrets

FREAK (CVE-2015-0204):
 Target: Export cipher suites (forced by 90s US regulations)
 Method: Force server to use RSA-EXPORT (512-bit) → factor in hours
 Impact: Decrypt HTTPS connections to affected servers
 Fix: Disable all EXPORT cipher suites

Logjam (CVE-2015-4000):
 Target: DHE-EXPORT (512-bit DH parameters)
 Method: Precompute discrete logarithm table for 512-bit primes
 NSA-scale attack feasible against 1024-bit primes
 Impact: Passive decryption of many HTTPS+VPN connections
 Fix: Minimum 2048-bit DH parameters, use ECDHE instead

ROBOT (2017):
 Target: RSA PKCS#1v1.5 padding in TLS
 Method: Bleichenbacher's 1998 oracle attack resurrected
 Server's different error responses for valid vs invalid padding
 Impact: Decrypt RSA-encrypted TLS sessions (if no forward secrecy)
 Affected: F5, Citrix, Cisco, Palo Alto, Radware, many others
 Fix: Constant-time RSA decryption, use ECDHE (no RSA key exchange)
# TLS security testing:

# Test TLS configuration comprehensively:
# testssl.sh (most comprehensive):
bash testssl.sh target.com:443

# Quick checks:
nmap --script ssl-enum-ciphers,ssl-heartbleed,ssl-poodle,ssl-dh-params \
 -p 443 target.com

# Check supported TLS versions:
for version in ssl2 ssl3 tls1 tls1_1 tls1_2 tls1_3; do
 if openssl s_client -connect target.com:443 -$version 2>/dev/null | \
 grep -q "CONNECTED"; then
 echo "$version: SUPPORTED"
 else
 echo "$version: NOT supported"
 fi
done

# Check certificate details and chain:
openssl s_client -connect target.com:443 -showcerts 2>/dev/null | \
 openssl x509 -noout -text | grep -E "Not After|Signature Algorithm|Public-Key:"

# Decrypt TLS traffic (requires pre-master secret log):
export SSLKEYLOGFILE=/tmp/ssl_keys.log
curl https://target.com/api/data # Keys logged
# Open in Wireshark: Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log

# Test HSTS:
curl -sI https://target.com | grep -i "strict-transport"
# max-age should be ≥31536000 (1 year)
# includeSubDomains recommended
# preload for browser preload list

# Certificate pinning test:
curl -sI --pinnedpubkey sha256//HASH= https://target.com
# If pinning correct: 200
# If wrong pin: SSL error

12. Cryptographic Randomness

12.1 Why Randomness Is Critical

Cryptography requires random numbers for key generation, IVs, salts, nonces, and ephemeral DH values. If these "random" values are predictable, the entire cryptographic system fails regardless of the strength of the algorithm.

What breaks when randomness is weak:

Key generation: Predictable private key → attacker knows your key without brute force
AES IV: Predictable IV → pattern in ciphertext, BEAST-like attacks
ECDSA nonce: Predictable k → private key recovery (PS3, Android Bitcoin wallet)
Salt: Predictable salt → precomputed table attacks possible
Session tokens: Predictable tokens → session hijacking without authentication
VPN key: Predictable key → full traffic decryption (DUHK attack 2017)

12.2 PRNG vs CSPRNG

PRNG (Pseudo-Random Number Generator):
 Deterministic algorithm that produces "random-looking" numbers
 Seeded with initial value
 Given seed: entire sequence is deterministic

 Examples: rand() in C, Math.random() in JavaScript
 Use for: simulation, games, non-security randomness
 NEVER use for: cryptographic keys, tokens, passwords, security

 Attack: if attacker knows seed (e.g., current timestamp), they can
 predict all "random" numbers → broken crypto

CSPRNG (Cryptographically Secure PRNG):
 Designed to be computationally infeasible to predict next output
 Even with knowledge of all previous output
 Forward secrecy: learning current state doesn't reveal past output
 Backward secrecy: predicting future output is infeasible

 Examples:
 Linux: /dev/urandom (modern Linux: uses CSPRNG, safe for all uses)
 Linux: /dev/random (legacy: blocks until entropy; /dev/urandom is preferred)
 Windows: CryptGenRandom, BCryptGenRandom
 OpenSSL: RAND_bytes()
 Python: os.urandom(), secrets module

/dev/random vs /dev/urandom (Linux):
 Myth: /dev/urandom is weaker than /dev/random
 Truth: Both use same CSPRNG kernel; /dev/random blocks unnecessarily
 Modern Linux (kernel 5.6+): both behave identically
 ALWAYS use: /dev/urandom or the secrets module
 NEVER block applications waiting for /dev/random

12.3 Entropy

Entropy in cryptography: measure of unpredictability (bits)

High entropy: 256-bit key from CSPRNG (truly unpredictable, 2^256 possibilities)
Low entropy: 256-bit key from timestamp (only milliseconds in a day)

Entropy sources (Linux kernel entropy pool):
 Hardware: CPU timing jitter, thermal noise, hardware RNG (RDRAND)
 Devices: Disk I/O timing, network packet arrival timing
 User: Keyboard/mouse timing
 Early boot: Low entropy problem (all sources above unavailable)

The "entropy starvation" problem:
 Embedded systems, VMs, and containers often lack entropy at boot

 Impact: If CSPRNG generates keys before sufficient entropy is collected:
 Keys may be predictable

 Real attack (2012): Heninger et al. analysed millions of RSA public keys
 Found many shared factors (same primes in different keys)
 Root cause: entropy-starved key generation at first boot
 Multiple different devices generated the same "random" primes

 Solution:
 Hardware RNG: Intel RDRAND instruction (hardware true RNG)
 virtio-rng: Feed entropy to VMs from host
 haveged: Software entropy daemon
 rng-tools: Hardware RNG interface daemon
# Cryptographic randomness in practice:

# Generate secure random values:
openssl rand -hex 32 # 32 bytes = 256-bit random key (hex)
openssl rand -base64 32 # 32 bytes as base64
openssl rand -out keyfile.bin 32 # Write 32 random bytes to file

# Python — ALWAYS use secrets module for cryptographic randomness:
python3 << 'EOF'
import secrets, os

# Secure token for session IDs, CSRF tokens, etc:
token = secrets.token_hex(32) # 64-char hex string (256 bits)
print(f"Secure token: {token}")

# Secure random bytes for key material:
key = secrets.token_bytes(32) # 32 random bytes
print(f"Key (hex): {key.hex()}")

# os.urandom() is equivalent and always cryptographically secure:
key2 = os.urandom(32)
print(f"os.urandom key: {key2.hex()}")

# WRONG: Do not use random module for security:
import random
insecure = random.randbytes(32)
# This is NOT cryptographically secure — don't use for keys/tokens/salts
# random.randbytes looks secure but can be predicted if seed is known
EOF

# Check entropy on Linux:
cat /proc/sys/kernel/random/entropy_avail # Current entropy bits available
cat /proc/sys/kernel/random/pool_size # Entropy pool size

# Check hardware RNG availability:
cat /sys/devices/virtual/misc/hw_random/rng_available
ls /dev/hwrng # Hardware RNG device

# Install entropy daemon for servers/VMs:
sudo apt install haveged
sudo systemctl start haveged
cat /proc/sys/kernel/random/entropy_avail # Should be much higher now

# Test PRNG quality (diehard/NIST tests):
openssl rand 1000000 > /tmp/random.bin
ent /tmp/random.bin # Entropy test (install: apt install ent)
# Entropy: should be close to 8.00 bits/byte
# Chi-square: should be within expected range
# Serial correlation: should be close to 0.00

Key Insight: Weak randomness is the silent killer of cryptographic systems. AES-256 with a predictable key provides no security. ECDSA with a repeated nonce loses the private key. Session tokens generated with timestamp seeds are trivially predictable. Always use CSPRNG (/dev/urandom, os.urandom(), secrets module) and never use general-purpose PRNGs (rand(), random.random()) for any security purpose.


13. Steganography

13.1 What Steganography Is

Steganography (Greek: "hidden writing") is the practice of concealing a message within another, non-secret, file or communication. Unlike cryptography, which makes content unreadable, steganography hides the existence of the message itself.

Steganography vs Cryptography:

Cryptography:
 "Hello World" → encrypted → "x7Kp2mQ9..." (obviously encrypted)
 Attacker knows: a secret message exists, cannot read it

Steganography:
 "Hello World" hidden inside a photo of a cat
 Attacker sees: a photo of a cat
 Attacker doesn't know: a secret message exists

Combined (crypto + stego):
 Encrypt "Hello World" → encrypt it → hide encrypted data in cat photo
 Even if stego is detected: encrypted content cannot be read
 This is what sophisticated threat actors and C2 channels use

13.2 Steganography Techniques

Image Steganography — LSB (Least Significant Bit):

 Each pixel in a 24-bit RGB image has: R(8 bits) G(8 bits) B(8 bits)
 Changing the least significant bit changes colour by 1/256 — visually imperceptible

 Original pixel: R=11010110, G=10010100, B=11100010
 Modified pixel: R=11010111, G=10010100, B=11100011
 (Changed LSB of R and B to embed 2 bits of hidden data)

 Capacity: 3 bits per pixel (one per RGB channel)
 24-bit 1920×1080 image: 1920×1080×3 = 6.2 million bits = ~750KB of hidden data

 Detection: Statistical analysis (chi-square test detects LSB pattern anomalies)
 Steganalysis tools: StegExpose, StegoSuite

Audio Steganography:
 Hide data in audio file LSBs (imperceptible to human hearing)
 Phase modification: hide in phase of audio signal
 Echo hiding: encode data in echo parameters

Network Steganography:
 ICMP payload: hide data in ping packet payload
 TCP timestamp: encode data in TCP timestamp option
 DNS: hide data in subdomain labels or response padding
 HTTP headers: hide in custom headers or timing

 This is particularly relevant for C2 (command and control):
 Malware uses network steganography to blend C2 traffic with legitimate traffic

13.3 Steganography in Security

Offensive uses:
 Data exfiltration: hide stolen data in images uploaded to social media
 C2 communication: hide commands in public social media posts/images
 Malware delivery: embed malware in documents, images

 Real examples:
 Turla APT (2019): hid C2 commands in comments on Britney Spears' Instagram posts
 Duqu malware: used custom steganography to exfiltrate data
 Multiple APT groups: use image steganography for C2 communications

Defensive considerations:
 DLP systems must inspect image content, not just file type
 Network monitoring must analyse payload patterns, not just protocols
 Outbound traffic should be analysed for steganographic channels
# Steganography in practice:

# steghide — hide data in JPEG/BMP/WAV/AU:
sudo apt install steghide

# Hide a file in an image:
steghide embed \
 -cf photo.jpg \  # Cover file (the innocent-looking carrier)
 -sf secret.txt \  # Secret file to hide
 -p "stegopassword" # Passphrase (encrypts the hidden data)

# Extract hidden data:
steghide extract \
 -sf photo.jpg \  # Stego file
 -p "stegopassword" # Passphrase
# Extracts secret.txt if passphrase correct

# stegseek — fast steghide password cracker:
stegseek photo.jpg /usr/share/wordlists/rockyou.txt

# zsteg — detect LSB steganography in PNG/BMP:
sudo gem install zsteg
zsteg suspicious_image.png # Detect hidden data
zsteg -a suspicious_image.png # Try all methods

# binwalk — find embedded files in any binary:
binwalk suspicious_file.jpg # Shows embedded files
binwalk -e suspicious_file.jpg # Extract embedded files

# exiftool — check metadata (stego sometimes in EXIF):
exiftool photo.jpg | grep -v "^$" # All metadata
exiftool -all= clean_photo.jpg # Strip ALL metadata

# Detect LSB steganography with statistical analysis:
python3 << 'EOF'
from PIL import Image
import numpy as np

def detect_lsb_stego(filename):
 img = Image.open(filename)
 pixels = np.array(img)

 # Get all LSBs
 lsbs = pixels & 1 # Extract LSB of each channel

 # Calculate expected vs actual distribution
 # In a natural image, LSBs should be ~50% 0, ~50% 1
 # LSB steganography makes it exactly 50% (or different pattern)
 ratio = lsbs.mean()
 print(f"LSB distribution: {ratio:.4f} (natural: ~0.5, suspicious: exactly 0.5)")

 # Chi-square test
 n = lsbs.size
 observed_0 = np.sum(lsbs == 0)
 observed_1 = np.sum(lsbs == 1)
 expected = n / 2
 chi_sq = ((observed_0 - expected)**2 + (observed_1 - expected)**2) / expected
 print(f"Chi-square: {chi_sq:.2f} (low value suggests steganography)")

detect_lsb_stego("photo.jpg")
EOF

Key Insight: Steganography's power is deniability — the carrier file appears innocent. Sophisticated APT groups use steganography for C2 because the traffic blends with normal image/media traffic. Defence requires content inspection (not just metadata), statistical analysis of image entropy, and anomaly detection on upload/download patterns. In incident response, always check media files for embedded content.


14. Cryptography in OT/ICS Environments

14.1 The Cryptography Gap in OT

State of cryptography in OT/ICS (2024):

No cryptography at all:
 Modbus TCP: no authentication, no integrity, no confidentiality
 DNP3 (baseline): no cryptography (SAv5 adds authentication)
 PROFIBUS: no cryptography
 BACnet: no cryptography in baseline

Why no cryptography:
 1. Designed in 1970s-1980s before network security was a concern
 2. CPU constraints: embedded PLCs lack processing power for crypto
 3. Latency constraints: crypto processing adds microseconds-milliseconds
 unacceptable for hard real-time control loops
 4. Legacy infrastructure: millions of deployed devices cannot be updated
 5. Vendor lock-in: vendors slow to implement standard crypto

Real consequence:
 Any device on the OT network segment can:
 - Read all sensor values (passive Modbus scan)
 - Write to any register/coil (change setpoints, open/close valves)
 - Replay captured commands (repeat a previous command)
 - Inject false commands (fabricate Modbus function codes)
 With no authentication required

14.2 Where Cryptography Exists in OT

IEC 62351 — Security for IEC 61850 and IEC 60870-5-104:
 62351-3: TLS for MMS, ICCP
 62351-4: Authentication for ICCP
 62351-5: Authentication for DNP3 and IEC 60870-5-101/104
 62351-6: GOOSE and Sampled Values authentication (AES-GMAC)
 62351-8: Role-based access control

 Adoption: low — implementation is complex, vendor support varies

OPC-UA Security:
 OPC-UA has built-in security: authentication, signing, encryption
 MessageSecurityMode: None, Sign, SignAndEncrypt
 Sign: Integrity protection (HMAC)
 SignAndEncrypt: Integrity + Confidentiality (AES-256-CBC)
 Certificates: X.509 certificates for server/client authentication

 This is the correct model for new OT deployments
 OPC-UA adoption growing — replacing older proprietary protocols

WirelessHART / ISA100.11a:
 AES-128 encryption for wireless industrial sensors
 CCM (Counter with CBC-MAC) mode — authenticated encryption
 Key management: join keys, session keys

DNP3 Secure Authentication v5 (SAv5):
 HMAC-based challenge-response authentication
 Prevents command injection for DNP3
 Adoption: some power utilities (NERC CIP drives adoption)

IEC 61850 GOOSE Security (IEC 62351-6):
 GOOSE messages authenticated with AES-GMAC
 Prevents forged protection relay commands
 Deployment: rare — latency constraints challenged

14.3 TLS in OT Environments

TLS deployment challenges in OT:

Certificate management:
 OT devices have long lifespans (10-20 years)
 Annual TLS certificate renewal cycles require:
 - Update process that doesn't interrupt operation
 - Certificate lifecycle management tooling
 - Operator training
 Many OT environments have no process for this

TLS versions on legacy OT:
 Windows CE, Windows XP embedded: support TLS 1.0 only (deprecated)
 Cannot be upgraded without replacing hardware
 Solution: TLS termination proxy (modern TLS toward IT, legacy toward OT device)

Self-signed certificates in OT:
 OT environments often cannot access internet PKI
 Internal CA or self-signed certificates used
 Risk: No validation possible without PKI

TLS for OT communication:
 OPC-UA → TLS 1.2/1.3 for secure machine-to-machine
 Remote access → TLS VPN or TLS-based remote access (not Telnet!)
 Historian → TLS for HTTPS data access from IT

Certificate pinning in OT:
 OT systems can pin specific certificates
 Prevents MITM even with compromised CA
 Requires careful management for certificate rotation
# Cryptography assessment in OT networks:

# Check if OT protocols are running without encryption:
sudo tcpdump -i eth0 -nn 'port 502 or port 20000 or port 2404 or port 44818' | \
 head -20
# If you see traffic: those protocols running in cleartext

# Check if OPC-UA is using TLS:
# Port 4840 = OPC-UA (unencrypted baseline)
# Port 4843 = OPC-UA with TLS
nmap -sV -p 4840,4843 192.168.1.0/24 2>/dev/null

# Test TLS on industrial historian or HMI:
openssl s_client -connect historian-server:443 2>/dev/null | \
 grep -E "Protocol|Cipher|Verify"
# Look for TLS 1.0/1.1 (deprecated) or weak cipher suites

# Check IEC 62351 GOOSE authentication (wireshark):
# Filter: goose
# Check if Security Level > 0 in GOOSE PDU
# Security Level 0 = no authentication (vulnerable)

# Audit OPC-UA security mode:
# Using open62541 or other OPC-UA client:
# python-opcua:
python3 << 'EOF'
try:
 from opcua import Client
 client = Client("opc.tcp://192.168.1.100:4840")
 client.connect()
 # If connected without security: no encryption or authentication
 security_mode = client.get_attribute(1, "SecurityMode")
 print(f"Security Mode: {security_mode}")
 # 1 = None (no security!)
 # 2 = Sign
 # 3 = SignAndEncrypt (correct)
 client.disconnect()
except Exception as e:
 print(f"Connection result: {e}")
EOF

15. Module Summary

Concept Core Mechanism Attack Relevance Key Defence OT/ICS Note
Encoding Format conversion (Base64, URL, Hex) WAF bypass via encoding, credential exposure in Basic Auth Decode all input before validation; never confuse with encryption OT firmware strings often Base64-encoded in memory dumps
Symmetric Encryption Same key encrypts and decrypts Brute force key, weak cipher (DES/3DES), ECB mode patterns AES-256-GCM; never ECB; unique random IV per message AES-128-CCM in WirelessHART; OT devices often lack AES-NI
AES SPN, 10-14 rounds, 128-bit blocks Side-channel (timing, cache); implementation attacks only AES-256-GCM standard; hardware AES-NI; protect key material AES-128 in WirelessHART; AES-256 for historian data at rest
DES/3DES 56-bit/112-bit Feistel; BROKEN DES: brute force in minutes; 3DES: SWEET32 birthday attack Eliminate; replace with AES-256 Legacy payment systems in OT; force replacement schedule
RSA Integer factorisation; public/private keys PKCS1v15 padding oracle (ROBOT 2017); short keys (ROCA) RSA-2048 minimum; RSA-PSS padding; prefer ECDH TLS certificates for OT historian, OPC-UA servers
ECC Elliptic curve discrete log; ECDHE Weak curve parameters (NIST distrust); ECDSA k reuse Curve25519/P-256; always random k in ECDSA OPC-UA certificates; preferred over RSA for constrained devices
Diffie-Hellman g^ab mod p shared secret without transmitting Logjam (512-bit precomputed); discrete log for weak params ECDHE; 2048-bit minimum DH; forward secrecy ECDHE in OPC-UA TLS; enables forward secrecy for OT sessions
MD5 128-bit Merkle-Damgård; BROKEN Collision (2009); forged CA cert (Flame 2012) SHA-256 minimum; MD5 acceptable only for non-security deduplication Legacy OT firmware checksums use MD5; identify and flag
SHA-1 160-bit; BROKEN SHAttered collision (2017, $100K); chosen-prefix 2020 SHA-256 minimum OT firmware updates still using SHA-1; critical finding
SHA-256/SHA-3 256-bit; SECURE No practical attack known SHA-256 standard; SHA-3 for diversity Use for firmware integrity verification in OT
Salt Random per-password value; defeats rainbow tables Without salt: precomputed table attack 16+ byte CSPRNG salt; unique per password; store with hash Hash-based authentication tokens in OT systems
Pepper Secret application-level addition to password Requires app server compromise in addition to DB breach 256-bit CSPRNG; store in HSM or config separate from DB HMI application authentication secrets
bcrypt/Argon2id Intentionally slow; work factor GPU cracking; requires work to crack even with hash Argon2id (time=3, mem=64MB); bcrypt (rounds≥12) SCADA operator passwords; HMI authentication
Digital Signatures Hash + asymmetric sign; auth + integrity + non-repudiation Key theft; PS3/Android k reuse; PKCS1v15 forgery ECDSA with random k; Ed25519; RSA-PSS IEC 62351 signing of GOOSE messages; OTA firmware signing
PKI Certificate chains; CA trust anchor Rogue CA (MD5 collision 2008); misissued certs CAA DNS records; CT monitoring; short-lived certs OPC-UA PKI; internal CA for OT certificates
TLS Asymmetric key exchange → symmetric data encryption Heartbleed, BEAST, POODLE, FREAK, Logjam, ROBOT TLS 1.3 minimum; ECDHE only; AEAD ciphers; HSTS TLS for OT historian, remote access, OPC-UA; never Telnet
TLS Handshake ClientHello/ServerHello → key exchange → application data Downgrade attack; session hijack; MITM (no cert validation) Certificate pinning; HSTS; validate full chain; TLS 1.3 OT remote access must validate server certificates
Cryptographic Randomness CSPRNG; entropy sources; unpredictable output Predictable seed (DUHK 2017); entropy starvation; ECDSA k /dev/urandom; secrets module; hardware RNG; haveged for VMs First-boot key generation in OT devices; entropy starvation risk
Steganography Hidden data in carrier files Data exfiltration; C2 in social media images (Turla APT) Content inspection; outbound media analysis; StegExpose ICMP tunnel C2 in OT networks; detect with payload analysis

Next Module: Stage 2.3 — Identity and Access Management

Previous Module: Stage 2.1 — Core Security Concepts

Stage Index: Stage 2 README

Series Index: Full Roadmap


This document is part of the Cybersecurity × OT/ICS Security Full Roadmap series. All techniques are presented for educational purposes, authorised security research, and defensive security practice. Always obtain proper authorisation before testing any system.