Message Authentication Codes
「 Overview 」
Use 「 In Order 」
Keyed BLAKE2b ( 256 | 512 )
- Faster than HMAC, BLAKE (what BLAKE2 was on)
- Provides the same practical level of security as SHA3
- Popular in software (Argon2 and many other password hashing schemes)
- Received a significant amount of cryptanalysis,
even more than Keccak (the SHA3 finalist),
as part of the SHA3 competition
HMAC SHA ( 256 | 512 )
Slower and older than BLAKE2b but well-studied.
SHA2 is also faster and far more available than SHA3, which has
seen somewhat limited adoption so far since SHA2 is still secure.
HMAC SHA3 ( 256 | 512 )
- SHA3 is slower than BLAKE2b and SHA2 in software
- But has a higher security margin than both
- And is fast in hardware.
Moreover, HMAC-SHA3 is needlessly inefficient because SHA3 is already a MAC.
The only reason I’m recommending HMAC-SHA3 is because SHA3 is designed to be
a replacement for SHA2, KMAC is rarely available, and you shouldn’t have to
construct a MAC using concatenation yourself in most scenarios.
Keyed BLAKE3 256
- Faster than HMAC, BLAKE2b, and SHA3
- But it has a smaller security margin
- Only targets the
128-bit security
level - And hasn’t been implemented in many cryptographic libraries yet
Avoid 「 Unordered | All Unsuitable 」
HMAC ( MD5 | SHA1 )
MD5 and SHA1 should no longer be used for anything.
(Regular) Unencrypted Hashes
SHA256( ciphertext )
This is insecure because unkeyed hashes don’t provide authentication.
(Regular) Encrypted Hashes
AES-CTR( SHA256( ciphertext ) )
This is insecure.
For example, with a stream cipher, you could flip bits in the ciphertext hash.
SHA2( Key || Message )
This is vulnerable to Length Extension Attacks , as
discussed in point 3 of the Notes in the Hashing section.
Technically speaking, SHA2(message || key)
works as a MAC if the attacker
doesn’t know the key, but it’s weaker than constructions like HMAC because it
requires the hash function to be collision resistant rather than a
pseudorandom function and therefore shouldn’t be used.
Newer hash functions, like BLAKE2b, SHA3, and BLAKE3, are resistant to
length extension attacks and could be used to perform Hash(key || message)
safely, but you should still just use a keyed hash function or HMAC instead
to do the work for you.
Poly1305
And Other Polynomial MACs
These produce small tags that are designed for online protocols and small messages.
They’re also easier to misuse than the recommended algorithms (e.g. Poly1305 requires
a secret, unique, and unpredictable key each time that’s independent from the encryption key).
CBC-MAC
This is unpopular and often implemented incorrectly because it has weird requirements
that most people are completely unaware of, allowing for attacks.
Even when implemented correctly, the recommended algorithms are better.
CMAC/OMAC
Almost nobody uses this, even though it improves
on CBC-MAC in terms of preventing mistakes.
128-bit ( Keyed Hashes | HMACs )
You shouldn’t go below a 256-bit output with hash functions
because 128-bit security
should be the minimum.
KMAC
Whilst more efficient than HMAC-SHA3, it seems to be rarely available.
Furthermore, it’s likely that HMAC-SHA3 will be the norm because
SHA3 is designed to replace SHA2, which is used with HMAC.
Notes
「 1 」
Please read points 14 - 17 of the Symmetric Encryption
notes for guidance on implementing a MAC correctly.
「 2 」
Please read point 2 of the Symmetric Key Size
Use section for guidance on what key size to use.
「 3 」
A 256-bit authentication tag is sufficient for most use cases
However, a 512-bit tag provides additional security
if you’re concerned about quantum computing.
I wouldn’t recommend bothering with an output length in-between
(HMAC-SHA384) because that’s not common, and you may as well
go all the way to get a 256-bit security
level.
「 4 」
Append the authentication tag to the ciphertext:
This is common practice and how AEADs operate.
「 5 」
Concatenating multiple variable length parameters can lead to attacks
HMAC(
Key : MacKey,
Message : AdditionalData | Ciphertext
)
If you fail to concatenate the lengths of the parameters
HMAC(
Key : MacKey,
Message : AdditionalData | Ciphertext | AdditionalDataLength | CiphertextLength
)
with the lengths converted to a fixed number of bytes consistently in either
big- or little-endian, regardless of the endianness of the machine) or always
ensure that they are fixed in size, then your implementation will be susceptible
to canonicalization attacks because an attacker can shift bytes in the different
parameters whilst producing a valid authentication tag.
AEADs do this length concatenation for you to prevent this.