Skip to content

1.2 Hash, MAC, KDF, and Password Storage

The security fortress has received four tools that look identical: hash functions, message authentication codes (MACs), key derivation functions (KDFs), and password hashing. Intelligence officers have tasked you with first distinguishing exactly what each one protects.

Hash functions, message authentication codes (MACs), key derivation functions (KDFs), and password hashing all produce a fixed-length byte output. But they solve fundamentally different problems. Using SHA-256(password) as a password storage mechanism, or applying a standard hash function to sign a message, is a misapplication, confusing similar interfaces with equivalent security semantics.

Ordinary Hashes Lack Secrets

text
digest = Hash(message)

Cryptographic hashes typically aim for preimage resistance, second-preimage resistance, and collision resistance. They are well-suited for content addressing, integrity fingerprints, and components of signing protocols.

However, anyone can recompute a standard hash. If an attacker can simultaneously replace both the file and its digest, SHA-256(file) cannot prove the file originated from a specific source. MD5 and SHA-1 are no longer suitable for collision-resistant scenarios; modern designs generally use SHA-256/384, SHA-3, or explicitly specified contemporary algorithms.

MAC Proof that a Key Holder Generated the Message

text
tag = HMAC(key, message)

HMAC incorporates a secret key into the authentication process. Since the verifier must possess the same key, it is well-suited for service-to-service webhooks, internal protocols, and ensuring data integrity in database fields.

During verification, use the library's constant-time comparison to avoid leaking the position of the first differing byte through standard string comparisons. Additionally, encode the protocol context into the message:

text
version || method || path || timestamp || body_digest

Each field must have unambiguous length or be encoded with normalization to prevent ambiguities like ab|c and a|bc during concatenation, which could break the protocol. To prevent replay attacks, also validate the time window and a one-time ID; a valid HMAC only proves the message was not altered, not that it was the first occurrence.

KDF for Deriving Isolated Subkeys

Don't use a master key for both encryption, MAC, token signing, and database field encryption. HKDF-based KDFs can derive subkeys with isolated purposes from input key material:

text
K_encrypt = HKDF(master, info="atlas/v1/encryption")
K_mac     = HKDF(master, info="atlas/v1/webhook-mac")

info enables domain separation. Even when the underlying master key is the same, different protocols and uses won't directly reuse the same output. HKDF is suitable for high-entropy key material, not for "making user-generated short passwords safe."

Passwords Need Intentionally Expensive, Dedicated Functions

User passwords often have low entropy, making them vulnerable to offline guessing once an attacker gains access to the database. Generic hash functions are too fast and actually assist attackers. Password verification should use a memory-hard password hashing function with an independent random salt, such as Argon2id:

text
encoded = Argon2id(password, random_salt, memory, iterations, parallelism)

The salt does not need to be kept secret. Its purpose is to ensure that identical passwords produce different verifier values, preventing attackers from precomputing hash tables that could compromise all accounts. Each record must store the algorithm, version, parameters, salt, and output, enabling future upgrades without breaking compatibility.

Parameters should not be hardcoded or static. They must be benchmarked under real production hardware and peak concurrency loads, tuned so that individual verification is slow enough to deter attackers but still within system capacity, with extra headroom to guard against login flood attacks. RFC 9106 provides reference configurations for Argon2id, but actual services must adjust based on available memory and denial-of-service risk.

A pepper is an additional server-side secret that can be stored in a KMS/HSM and injected before and after hashing using a reviewed, auditable method. It ensures that an attacker who only compromises the database lacks a complete set of inputs, but adds complexity to rotation and disaster recovery procedures. A pepper cannot replace the salt or a properly configured KDF.

Login Verification Should Support Progressive Upgrades

text
Read record → Validate record parameters
        → If parameters are outdated, recalculate using updated parameters upon successful login

This approach enables gradual improvement of security costs without requiring knowledge of the user's plaintext password. Accounts that remain inactive for extended periods can be forcibly reset in the event of a security incident.

Password policies also directly impact real-world security. NIST SP 800-63B-4 does not recommend enforcing rigid combinations of uppercase, lowercase, numbers, and special characters. Instead, it supports longer passwords and password manager paste functionality, discourages common or previously leaked passwords, limits online guessing attempts, and requires password changes when evidence of compromise is detected, rather than mandating periodic, arbitrary rotations.

A single-factor password must be at least 15 characters long; shorter passwords may be permitted as part of a multi-factor authentication flow, but no shorter than 8 characters. This reflects NIST's recommended scenarios, not a universal requirement for all products to mechanically enforce the same minimum length. Businesses must still model password requirements based on their identity assurance levels and regulatory obligations.

Confusing Relationships

RequirementShould ConsiderShould Not Use Directly
File content fingerprintSHA-256 and similar hash functionsPassword hash functions that include secrets
Message authentication with shared keysHMAC`Hash(key
Deriving usage keys from a master keyHKDFDirectly extracting bytes from the master key
Storing user passwordsArgon2id and similar password hash functionsSHA-256, reversible encryption
Preventing webhook replay attacksMAC combined with time/nonce stateOnly MAC alone

Next lesson, we explore asymmetric cryptography: public-key cryptography solves key distribution and signing problems, but it does not make arbitrary data suitable for "direct RSA encryption."

References

Built with VitePress | Software Systems Atlas