NETWORKING MASTERY · PHASE 5 · MODULE 19 · WEEK 17
🔐 Cryptography Foundations
Symmetric encryption · Asymmetric crypto · Hash functions · MACs · Key exchange · PKI · Random numbers
Intermediate → Advanced Prerequisite: M05 TCP Essential for TLS and IPsec 2 Labs

THREE SECURITY PROPERTIES CRYPTOGRAPHY PROVIDES

🔐

Confidentiality, Integrity, and Authentication

OVERVIEW

Every cryptographic protocol in networking — TLS, IPsec, SSH, WireGuard — provides some combination of three fundamental properties. Understanding what each primitive provides (and what it doesn't) is how you reason about security protocols.

  • Confidentiality — only the intended recipient can read the data. Provided by encryption (AES, ChaCha20). Does NOT guarantee the data wasn't modified.
  • Integrity — the data was not modified in transit. Provided by MACs (HMAC-SHA256) or AEAD ciphers (AES-GCM). Does NOT tell you who sent it.
  • Authentication — you are communicating with who you think you are. Provided by digital signatures (RSA, ECDSA) + PKI. Does NOT keep data confidential.

Most protocols combine all three: TLS uses asymmetric crypto for authentication + key exchange, then symmetric AEAD for confidentiality + integrity of the data stream. IPsec uses IKE for authentication + key exchange, then ESP for confidentiality + integrity.

SYMMETRIC ENCRYPTION — FAST, SHARED-KEY CIPHERS

🔑

AES and ChaCha20 — Modern Symmetric Ciphers

SYMMETRIC
/* Symmetric encryption: same key encrypts and decrypts */
/* Problem: how do two parties share the key securely? → Key Exchange (Tab 4) */

/* AES (Advanced Encryption Standard) */
Block cipher: processes 128-bit (16-byte) blocks
Key sizes:    128, 192, or 256 bits (AES-128, AES-192, AES-256)
Structure:    10/12/14 rounds of SubBytes + ShiftRows + MixColumns + AddRoundKey
Hardware:     AES-NI CPU instructions (x86 since 2010) — ~1 cycle/byte on modern CPUs

/* Block cipher modes — how to encrypt more than 16 bytes */
ECB (Electronic Codebook):  Same plaintext → same ciphertext. NEVER USE.
CBC (Cipher Block Chaining): XOR with previous ciphertext block. Needs IV. Padding required.
CTR (Counter):              Turns AES into a stream cipher. Parallelisable. No padding.
GCM (Galois/Counter Mode):  CTR + GHASH authentication tag. AEAD. Standard for TLS 1.3.

/* AEAD — Authenticated Encryption with Associated Data */
/* Single primitive providing both confidentiality AND integrity */
AES-128-GCM:  AES-CTR encryption + GHASH-128 authentication tag (16 bytes)
AES-256-GCM:  Same with 256-bit key
ChaCha20-Poly1305: ChaCha20 stream cipher + Poly1305 MAC
              No AES-NI needed — fast on mobile/ARM/embedded

/* AEAD inputs and outputs */
Encrypt:
  Input:  key, nonce (12 bytes), plaintext, AAD (additional auth data)
  Output: ciphertext (same length as plaintext) + auth_tag (16 bytes)

Decrypt:
  Input:  key, nonce, ciphertext, auth_tag, AAD
  Output: plaintext (if tag verifies) OR reject (if tag fails)

/* Critical: nonce MUST be unique per (key, message) */
/* Nonce reuse with AES-GCM → catastrophic key recovery possible */
/* TLS 1.3 uses XOR of static IV with sequence number as nonce */

/* OpenSSL AEAD in C */
EVP_AEAD_CTX *ctx = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(),
    key, 16, EVP_AEAD_DEFAULT_TAG_LENGTH);
EVP_AEAD_CTX_seal(ctx, ciphertext, &clen, max_out,
    nonce, 12, plaintext, plen, aad, aad_len);
EVP_AEAD_CTX_open(ctx, plaintext, &plen, max_out,
    nonce, 12, ciphertext, clen, aad, aad_len);

ASYMMETRIC CRYPTOGRAPHY — PUBLIC KEY SYSTEMS

🔒

RSA and Elliptic Curve Cryptography

ASYMMETRIC

Asymmetric (public-key) cryptography uses a mathematically linked key pair: the public key is freely distributed, the private key is secret. Operations with one key can only be verified/reversed with the other. This solves the key distribution problem — you can publish your public key to the world without compromising security.

/* RSA — Rivest-Shamir-Adleman */
Based on: hardness of factoring large integers (n = p × q)
Key sizes: 2048 bits minimum (currently safe), 4096 for long-term
Use cases: digital signatures, key encapsulation (encrypting a small key)
NOT used for: bulk data encryption (too slow — 1000× slower than AES)
Performance: ~1ms per RSA-2048 sign, ~0.1ms verify on modern CPU

/* RSA signature */
Sign:   sig = m^d mod n    (private key d)
Verify: m   = sig^e mod n  (public key e)
/* In practice: sign H(message) not message itself */
/* Padding: PKCS#1 v1.5 (legacy) or PSS (modern, recommended) */

/* Elliptic Curve Cryptography (ECC) */
Based on:  hardness of ECDLP (Elliptic Curve Discrete Logarithm Problem)
Key sizes: 256-bit ECC ≈ 3072-bit RSA security
           384-bit ECC ≈ 7680-bit RSA security
Performance: 10-20× faster than equivalent RSA
Curves:
  P-256 (secp256r1/prime256v1): NIST standard, TLS/HTTPS default
  P-384 (secp384r1):             Higher security, government use
  X25519 (Curve25519):           Bernstein curve, fastest, used in TLS 1.3 + WireGuard
  Ed25519:                        EdDSA signatures — fast, no random nonce needed

/* ECDSA — Elliptic Curve Digital Signature Algorithm */
/* Standard for TLS certificates (alongside RSA) */
/* WARNING: ECDSA requires a unique random nonce per signature */
/* Nonce reuse → private key recovery (PS3 hack, Bitcoin theft) */
/* Solution: use Ed25519 (EdDSA) which derives nonce deterministically */

/* Key generation with OpenSSL */
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec_key.pem
openssl pkey -in ec_key.pem -pubout -out ec_pub.pem
openssl genpkey -algorithm Ed25519 -out ed_key.pem

HASH FUNCTIONS AND MACs — INTEGRITY PRIMITIVES

🧮

Cryptographic Hash Functions

HASH
/* Cryptographic hash function properties */
1. Deterministic:     same input → always same output
2. One-way:           given H(x), computationally infeasible to find x
3. Collision resistant: hard to find x≠y such that H(x) = H(y)
4. Avalanche effect:  one bit change in input → ~50% output bits change

/* Hash algorithms — current recommendations */
SHA-256:   256-bit output, 64 rounds. Standard for most uses.
SHA-384:   384-bit output, truncated SHA-512. Faster on 64-bit.
SHA-512:   512-bit output, 80 rounds. Higher collision resistance.
SHA-3:     Different construction (Keccak sponge). Backup if SHA-2 broken.
BLAKE3:    Modern, faster than SHA-256, used in WireGuard, Bao.

MD5, SHA-1: BROKEN — do not use for security. Still used for checksums.

/* HMAC — Hash-based Message Authentication Code */
HMAC-K(m) = H( (K ⊕ opad) || H( (K ⊕ ipad) || m ) )
/* Provides: integrity + authentication (proves sender has key K) */
/* Does NOT provide: confidentiality */

HMAC-SHA256: 256-bit authentication tag
HMAC-SHA384: 384-bit tag (used in IPsec/IKEv2 PRF)

/* HKDF — HMAC-based Key Derivation Function (RFC 5869) */
/* Extract-then-Expand: derive multiple keys from one master secret */

/* Extract phase */
prk = HMAC-SHA256(salt, ikm)    /* input keying material → pseudorandom key */

/* Expand phase */
OKM = T(1) || T(2) || ... where T(i) = HMAC-SHA256(prk, T(i-1) || info || i)

/* TLS 1.3 uses HKDF to derive all session keys from the master secret */
/* IPsec uses PRF (usually HMAC-SHA256 or AES-XCBC) similarly */

/* OpenSSL hash in C */
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256((unsigned char *)msg, msg_len, digest);

/* HMAC in C */
unsigned char hmac[32];
unsigned int hlen;
HMAC(EVP_sha256(), key, key_len, data, data_len, hmac, &hlen);

KEY EXCHANGE — SECURE SHARED SECRET OVER PUBLIC CHANNEL

🤝

Diffie-Hellman and ECDH

KEY EXCHANGE

Key exchange protocols allow two parties to derive the same shared secret over a completely public, observable channel — without ever transmitting the secret. This solves the fundamental problem of symmetric cryptography: how to agree on a key when you have no pre-shared secret.

/* Diffie-Hellman Key Exchange — conceptual */
Public parameters: prime p, generator g (both public, known to attacker)

Alice chooses secret a, sends A = g^a mod p  (public)
Bob   chooses secret b, sends B = g^b mod p  (public)

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

Both arrive at S = g^(ab) mod p without ever transmitting a or b.
Attacker sees: g, p, A, B — but computing a from A = g^a mod p is the
discrete logarithm problem — computationally infeasible for large p.

/* ECDH — Elliptic Curve Diffie-Hellman */
Same concept on elliptic curves. X25519 is the modern standard:
  - Curve25519 points, 255-bit coordinates
  - Used in TLS 1.3, WireGuard, Signal Protocol
  - 32-byte keys, ~100µs per key exchange on modern CPU
  - Immune to timing attacks (constant-time implementation)

/* Forward Secrecy (Perfect Forward Secrecy) */
Key property: even if long-term private key is compromised later,
past session keys cannot be recovered.

Achieved by: ephemeral key exchange (generate new DH keypair per session)
TLS 1.3: ECDHE (Ephemeral) — mandatory forward secrecy
TLS 1.2: may use static RSA key exchange — no forward secrecy!
          "RSA key exchange": client encrypts premaster secret with server cert public key
          If server private key leaked → all past recorded sessions decryptable.

/* ECDH in OpenSSL C */
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY *pkey = NULL;
EVP_PKEY_keygen(ctx, &pkey);   /* generate ephemeral keypair */

/* After receiving peer's public key: */
EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_derive_init(dctx);
EVP_PKEY_derive_set_peer(dctx, peer_pubkey);
size_t slen;
EVP_PKEY_derive(dctx, shared_secret, &slen);  /* 32-byte X25519 secret */

💡 Forward secrecy is non-negotiable for modern security. Without it, an adversary who records encrypted traffic today and later compromises your server's private key can decrypt everything retroactively. This is why TLS 1.3 mandates ECDHE and removed static RSA key exchange. IPsec IKEv2 also uses ephemeral DH for the same reason.

PKI — PUBLIC KEY INFRASTRUCTURE

🏛️

X.509 Certificates and the CA Trust Chain

PKI

A public key alone doesn't tell you who it belongs to. PKI binds a public key to an identity (domain name, organisation) via a digitally signed certificate. Trust is established through a chain of signatures from a trusted root CA.

/* X.509 certificate key fields */
Version:          3 (current standard)
Serial Number:    unique per CA (used for revocation)
Issuer:           who signed this cert (CA name)
Subject:          who this cert is for ("CN=www.google.com, O=Google LLC")
Validity:         NotBefore and NotAfter (expiry)
Subject Public Key: the public key (RSA or EC) + algorithm
Extensions:
  Subject Alt Names (SAN): all domain names cert is valid for
  Key Usage:        what the key can do (digitalSignature, keyEncipherment)
  Extended Key Usage: TLS server auth, TLS client auth, code signing
  Basic Constraints: is this a CA cert? (isCA=true/false, path length)
Signature:        CA's signature over everything above

/* Chain of trust */
Root CA (self-signed, in browser/OS trust store)
  → Intermediate CA (signed by Root CA)
      → Leaf certificate (signed by Intermediate CA, has your domain)

/* Certificate validation */
1. Verify leaf cert signature using intermediate CA's public key
2. Verify intermediate CA signature using root CA's public key
3. Root CA is self-signed — trust must come from trust store
4. Check validity period (not expired)
5. Check Subject Alt Names — does CN/SAN match the domain?
6. Check revocation (CRL or OCSP)

/* OpenSSL certificate inspection */
openssl x509 -in cert.pem -text -noout   # full cert details
openssl x509 -in cert.pem -dates         # validity period
openssl s_client -connect google.com:443 -showcerts  # live cert chain
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt cert.pem

/* Certificate transparency (CT) */
# All public TLS certs must be logged to CT logs
# Browsers require SCT (Signed Certificate Timestamp) in TLS handshake
# Enables detection of mis-issued certs (NGFW relevance: detect rogue CAs)

/* OCSP Stapling */
# Server fetches OCSP response (revocation status) from CA
# Staples it to TLS handshake — client doesn't need to query CA separately
# NGFW: inspect OCSP status of presented certificates

ALGORITHM SELECTION REFERENCE

📋

Current Best-Practice Algorithm Choices

REFERENCE
PurposeRecommended (2024+)AcceptableAvoid
Symmetric encryptionAES-256-GCM, ChaCha20-Poly1305AES-128-GCMAES-CBC, AES-ECB, 3DES, RC4
Hash / digestSHA-256, SHA-384, BLAKE3SHA-512MD5, SHA-1 (security), SHA-224
MAC / HMACHMAC-SHA256, Poly1305HMAC-SHA384HMAC-MD5, HMAC-SHA1
Key exchangeX25519, ECDH P-256FFDHE-3072Static RSA, DH-1024/2048, ECDH P-192
Digital signaturesEd25519, ECDSA P-256RSA-PSS-2048ECDSA with bad RNG, RSA-PKCS1-1.5, DSA
Password hashingArgon2id, bcrypt(cost≥12)scryptSHA-256(password), MD5(password)
Random numbersgetrandom(), /dev/urandomCSPRNG from OpenSSLrand(), srand(time()), /dev/random blocking
Post-quantum (future)CRYSTALS-Kyber (KEM), CRYSTALS-Dilithium (sig)Hybrid classical+PQPure classical for PQ-sensitive data

Key Sizes — Security Level Reference

Security LevelSymmetricRSA/DHECCGood Until
128-bitAES-1283072 bitsP-256 / X255192030+
192-bitAES-1927680 bitsP-3842040+
256-bitAES-25615360 bitsP-5212050+
LAB 1

Hands-On Cryptographic Primitives with OpenSSL

Objective: Implement and test each primitive: AEAD encrypt/decrypt, HMAC, HKDF, ECDH key exchange, and certificate parsing.

1
AEAD: Write a C program that AES-128-GCM encrypts a test message. Verify: (a) decryption recovers plaintext, (b) flipping one byte of ciphertext causes authentication failure, (c) changing the nonce causes failure. Document what "authentication tag" bytes look like in the output.
2
HMAC: Compute HMAC-SHA256 of "Hello, World" with key "secret". Verify with: echo -n "Hello, World" | openssl dgst -sha256 -hmac "secret". Then implement HKDF extract+expand in Python using the hmac module. Derive 3 separate 32-byte keys from one 32-byte master secret.
3
ECDH: Generate two X25519 keypairs (Alice and Bob). Compute Alice's shared secret using Bob's public key and vice versa. Verify they produce the same 32 bytes. This is exactly what TLS 1.3 does during the handshake. Time the operation — how many key exchanges per second can your CPU do?
4
Certificate parsing: fetch a live TLS certificate: openssl s_client -connect github.com:443 2>/dev/null | openssl x509 -text -noout. Identify: issuer, subject, SANs, key type and size, validity period, CT SCT extension. Verify the certificate chain: does github.com use RSA or EC? What intermediate CA signed it?
LAB 2

Build a Secure Channel from Primitives

Objective: Build a minimal secure channel over a TCP socket using ECDH + HKDF + AES-GCM — demonstrating how TLS-like security can be constructed from primitives.

1
Client and server each generate an X25519 ephemeral keypair. Exchange public keys over the TCP connection (cleartext — this simulates the TLS ClientHello/ServerHello key share exchange). Compute the shared ECDH secret on both sides.
2
Run HKDF over the ECDH shared secret (with a fixed salt and "our-protocol-v1" as the info string). Extract two 32-byte keys: one for client→server encryption, one for server→client encryption. This is the key schedule step.
3
Use AES-256-GCM with the derived keys to encrypt/decrypt messages. Use a 64-bit sequence number as the nonce (zero-padded to 12 bytes). Send 5 encrypted messages each direction. Verify: each message has a unique nonce, decryption succeeds, and a tampered ciphertext is rejected.
4
Identify what your channel is missing compared to real TLS: (a) server authentication — no certificate, MITM possible; (b) client authentication — no mutual TLS; (c) protocol negotiation — no cipher suite selection. Document what TLS adds on top of these primitives.

M19 MASTERY CHECKLIST

When complete: Move to M20 - TLS Internals — now that you understand the primitives, the TLS protocol will make complete sense as the composition of exactly these building blocks.

← M18 VPP 🗺️ Roadmap Next: M20 - TLS →