Message Authentication

Cryptography Fundamentals

Chapter 8 · Message Authentication — MACs, HMAC & AEAD

Chapter 7 introduced hash functions as tools for integrity checking — but a plain hash, sent alongside a message with no other protection, turns out to guarantee almost nothing on its own. This chapter covers the missing ingredient: binding an integrity check to a secret, so only someone who holds it can produce a valid one — and finally explains, properly, what GCM's authentication tag from Chapter 6 was actually doing the whole time.

Why a Plain Hash Isn't Enough

Imagine a sender transmits a message along with its SHA-256 hash, so the receiver can verify nothing was altered in transit. An attacker intercepting this in transit can simply:

  1. Tamper with the message however they like.
  2. Recompute the SHA-256 hash of their tampered message — this requires no secret at all, anyone can run SHA-256.
  3. Forward the tampered message along with this newly-recomputed, perfectly valid hash.

The receiver checks the hash, finds it matches, and accepts the tampered message as genuine. The hash was never wrong — it correctly hashed the (tampered) message it was given. A plain hash verifies "this message wasn't altered after I computed this specific hash," which is completely useless against an attacker who can just recompute a fresh one.

MACs — Message Authentication Codes

A MAC is a hash-like function that also takes a secret key: MAC(key, message). Only someone who holds the key can produce a valid MAC for a given message. The sender computes the MAC and sends it alongside the message; the receiver, who also holds the key, recomputes the MAC independently and checks it matches.

This directly closes the gap from the previous section: an attacker who tampers with the message can no longer just recompute a matching value, because doing so requires the secret key they don't have. A mismatched MAC means either the message was altered, or it wasn't produced by someone holding the real key — either way, it's rejected.

HMAC — Hash-based MAC

Rather than design an entirely new primitive for MACs, HMAC is the standard way of building a MAC out of an existing hash function you already trust (Chapter 7's SHA-256, for instance). Conceptually:

HMAC(key, message) = Hash( (key XOR outerPad) || Hash( (key XOR innerPad) || message ) )

The nested, double-hashing structure isn't decoration — it exists specifically to defend against a real weakness in naive approaches like simply computing Hash(key || message) directly. Some hash constructions (including the Merkle-Damgård structure behind SHA-1 and SHA-2, from Chapter 7) allow an attacker who knows a hash's output — without knowing the original input — to compute a valid hash for that input with extra data appended to it. This is called a length-extension attack, and it's a real, demonstrated weakness in the naive construction. HMAC's specific nested design was engineered to resist it.

Verifying a MAC — Constant-Time Comparison

A subtle but very real implementation pitfall
A naive byte-by-byte comparison that stops and returns "false" the instant it finds a mismatched byte leaks timing information — a comparison that fails on the very first byte returns fractionally faster than one that fails on the tenth byte. An attacker who can measure response timing precisely enough can exploit this to guess a valid MAC one byte at a time, dramatically faster than brute-forcing the whole thing at once. Correct implementations always use a constant-time comparison function, which takes exactly the same amount of time regardless of where (or whether) a mismatch occurs — a good reminder, echoing Chapter 5's "never roll your own crypto," that even comparing two values correctly is a real, easy-to-get-wrong detail.

Encrypt-then-MAC vs. MAC-then-Encrypt vs. Encrypt-and-MAC

Combining a cipher (Chapters 5-6) with a MAC can be done in three different orders, and the choice genuinely matters:

SchemeHow it worksVerdict
Encrypt-then-MACEncrypt the plaintext, then compute the MAC over the ciphertextRecommended — the MAC can be checked before decryption is ever attempted
MAC-then-EncryptCompute the MAC over the plaintext, then encrypt both togetherHistorically used by early TLS versions; a contributing factor in several real TLS vulnerabilities
Encrypt-and-MACEncrypt the plaintext and MAC the plaintext independently, send bothUsed by SSH; the MAC is computed over unencrypted data, which can leak information in some cases

Encrypt-then-MAC's advantage is concrete, not theoretical: because the MAC covers the ciphertext, the receiver can verify it and reject a tampered message before ever decrypting attacker-controlled data. This is exactly the standard defense against Chapter 6's padding oracle attacks — if a tampered ciphertext is rejected by the MAC check first, the vulnerable padding-error behavior that a padding oracle attack depends on is never even reached.

AEAD — What GCM Was Actually Doing All Along

Chapter 6 introduced GCM as bundling confidentiality, integrity, and authenticity into one primitive, without fully explaining how. Now it can be stated precisely: GCM's authentication tag is built from GMAC, a MAC construction specialized for GCM's own CTR-mode-based encryption — and the overall structure of GCM is, in essence, encrypt-then-MAC baked directly into a single, efficient primitive, rather than two separate operations bolted together by hand. That's the real technical answer behind Chapter 6's "mode-of-operation-level" preview.

Associated Data — Authenticating Without Encrypting

Sometimes part of a message genuinely needs to stay readable — a network packet's routing header, say, needs to be visible before decryption can even happen — while still being protected from tampering. AEAD ciphers support this directly via associated data: extra data that's included in the authentication tag's computation (so tampering with it is detected) but is never encrypted at all. A network packet with an unencrypted header (needed for routing) and an encrypted payload, both covered by one authentication tag, is the textbook example.

Closing the loop from Chapter 1
Chapter 1's very first exercise asked what encryption alone does and doesn't guarantee — confidentiality, and nothing else. This chapter is the other half of that answer: a MAC alone gives integrity and authenticity but no confidentiality at all; encryption alone (Chapters 5-6) gives confidentiality but no integrity or authenticity; AEAD (GCM, or a properly-built encrypt-then-MAC construction) is what actually satisfies three of Chapter 1's four goals together in one primitive.

Hands-On Exercises

Exercise 1

Walk through, step by step, why sending a message alongside a plain (unkeyed) SHA-256 hash provides no real protection against a tampering attacker, and explain specifically what a MAC adds that a plain hash lacks.

📄 View solution
Exercise 2

A developer proposes building a MAC as simply SHA256(key || message) rather than using HMAC. Explain, conceptually, why this naive construction is considered unsafe, and what specific problem HMAC's nested double-hash structure is designed to prevent.

📄 View solution
Exercise 3

Of encrypt-then-MAC, MAC-then-encrypt, and encrypt-and-MAC, which scheme is safest against Chapter 6's padding oracle attack, and why specifically? Explain what happens differently at the moment a tampered ciphertext arrives.

📄 View solution

Chapter 8 Quick Reference

  • A plain hash provides no authenticity — anyone can recompute one for tampered data; needs a secret to be meaningful
  • MAC = a keyed hash-like function; only the key holder can produce a valid one for given data
  • HMAC — the standard way to build a MAC from a hash function; its nested structure defends against length-extension attacks
  • MAC comparison must be constant-time — a naive early-exit comparison leaks timing information exploitable byte by byte
  • Encrypt-then-MAC is the recommended combination order — lets tampered ciphertext be rejected before decryption is ever attempted, closing off padding oracle attacks
  • GCM (Ch.6) is, underneath, essentially encrypt-then-MAC built into one efficient AEAD primitive, using GMAC
  • Associated data — authenticated but left unencrypted, for data (like packet headers) that must stay readable
  • Next chapter: Public-Key Cryptography — RSA, Diffie-Hellman & Elliptic Curves, leaving the shared-secret world of symmetric crypto behind