Skip to main content

Integrity & Authentication

Confidentiality hides data, but it does not tell you whether the data arrived unchanged or came from who you think. Those are two more security goals: integrity (the message was not tampered with) and authentication (the sender is genuinely who they claim to be). Cryptographic hashes, MACs, and digital signatures build these up in layers.

Message integrity with hashes

A cryptographic hash (like SHA-256) turns any message into a fixed-size fingerprint. Two properties make it useful: the same input always yields the same hash, and changing even one bit of the input produces a completely different, unpredictable hash. If you send a message plus its hash, the receiver can re-hash the message and compare.

But a hash alone is fragile: an attacker who alters the message can simply recompute the hash to match. A plain hash detects accidental corruption, not a deliberate attacker.

caution

Anyone can compute a hash. If a message and its hash both travel over the network, an attacker can change the message and attach a fresh, valid hash. A hash tells you the bits are internally consistent - it does not tell you who produced them. For that you need a secret (a MAC) or a private key (a signature).

How hard is it to find a hash collision?

SHA-256 produces a 256-bit (32-byte) output, so there are 2^256 possible hashes - an astronomically large space. But the number of hashes you must try before finding any two that collide is not 2^256, it is roughly the square root of that, about 2^128, because of the birthday paradox (the same math that makes it likelier than you'd guess for two people in a room of 23 to share a birthday). 2^128 is still about 3.4 x 10^38 attempts - far beyond what any computer on Earth could do before the heat death of the universe - which is why SHA-256 is considered collision-resistant in practice. Older hashes did not fare so well: MD5 (128-bit output, so only 2^64 for a birthday collision) was broken in hours on ordinary hardware by 2004, and SHA-1 (2^80) fell to a practical collision in 2017. That history is exactly why TLS and code-signing systems moved off MD5 and SHA-1 to SHA-256 or better.

MACs - hashing with a shared key

A MAC (Message Authentication Code) fixes the attacker problem by mixing a shared secret key into the hash. Only someone who knows the key can produce a valid MAC, so a matching MAC proves both that the message is unchanged and that it came from someone holding the key. The limitation is the same as symmetric encryption: both sides must already share the secret.

A naive MAC comparison leaks the answer one byte at a time

Verifying a MAC means comparing the one you received against the one you computed. Do that with a normal string/byte-array equality check (like == in most languages) and the comparison typically short-circuits: it returns false the instant it finds a mismatched byte. That means a request whose first byte happens to match takes fractionally longer to reject than one that does not - and an attacker who can measure response timing precisely enough (this has been demonstrated over real networks, not just locally) can recover the correct MAC one byte at a time, trying 256 values per position instead of brute-forcing the whole thing at once. This exact class of bug has hit production authentication code in the wild. The fix is a constant-time comparison function (e.g. hmac.compare_digest in Python, crypto.timingSafeEqual in Node) that always compares every byte regardless of where the first mismatch falls.

Digital signatures

A digital signature uses public-key cryptography instead of a shared secret. The sender signs with their private key; anyone can verify with the matching public key. Because only the holder of the private key could have produced the signature, this gives integrity, authentication, and non-repudiation - the signer cannot later deny it. Unlike a MAC, no shared secret is needed, so signatures work between parties who have never met.

Certificates and the chain of trust

Signatures verify against a public key - but how do you know a public key really belongs to bank.com and not an impostor? A certificate answers this: it is a document binding a public key to an identity, signed by a Certificate Authority (CA).

Your device already trusts a small set of root CAs. A website's certificate is signed by an intermediate CA, whose certificate is in turn signed by a root CA. Following those signatures from the site up to a trusted root is the chain of trust:

  1. The site presents its certificate (its public key + identity, signed by a CA).
  2. You verify the CA's signature using the CA's public key.
  3. You verify that CA's certificate against the next one up, until you reach a root CA your device already trusts.

If every signature in the chain checks out, you can trust that the public key truly belongs to that site - and everything built on top (signatures, key exchange) becomes trustworthy too.