A message authentication code (MAC) protects a message’s integrity and authenticity with a shared secret key. It turns a message and key into a deterministic authentication tag: the same key and message produce the same tag, while someone without the key should not be able to forge one. section 3.0 section 3.1
Protecting a stateless cookie
A server can place a username and its authentication tag in a browser cookie. When the cookie returns, the server recomputes the tag from its secret key and the received username. A modified username produces a different tag, so the server rejects the request. A public hash alone fails because an attacker can modify the username and recompute its hash. section 3.1
A basic MAC exchange follows these steps:
- Share the same secret key between the sender and receiver. section 3.2
- Compute an authentication tag from the key and message. section 3.1
- Send the message together with its tag. section 3.2
- Recompute the tag and compare it with the received tag using a constant-time verification function. section 3.3.4 section 3.7
Figure 3.3 The interface of a message authentication code (MAC). The algorithm takes a secret key and a message, and deterministically produces a unique authentication tag. Without the key, it should be impossible to reproduce that authentication tag.
Shows the MAC interface: a secret key and message deterministically produce an authentication tag that should be unreproducible without the key. section 3.1
A MAC does not provide confidentiality: an observer may still read the message. Its primary guarantee is resistance to forgery, even when an attacker can request tags for many chosen messages. Keep the key random and secret, serialize structured data unambiguously, and use tags of at least 128 bits. section 3.3.1 section 3.3.2
Avoid these common MAC failures:
- Do not authenticate messages with a public hash alone; attackers can recompute it after tampering. section 3.1
- Do not use a naïve MAC protocol when an old valid message could be accepted again; add an incrementing counter or another replay protection mechanism. section 3.3.3
- Do not compare tags with an ordinary early-exit comparison; timing differences can reveal the tag byte by byte. section 3.3.4
- Do not construct a MAC by hashing a secret and message casually; use a standardized construction such as HMAC or KMAC. section 3.7
HMAC in practice
HMAC is a widely used MAC built from a hash function, commonly SHA-2. In a Rust exchange, the sender computes HMAC-SHA256 over the message, and the receiver independently verifies the received tag with the same key. The protocol authenticates integrity but still permits replay unless the message includes suitable freshness data. section 3.2 section 3.5.1
Listing 3.1 Sending an authenticated message in Rust
use sha2::Sha256;
use hmac::{Hmac, Mac, NewMac};
fn send_message(key: &[u8], message: &[u8]) -> Vec<u8> {
let mut mac = Hmac::<Sha256>::new(key.into()); #1
mac.update(message); #2
mac.finalize().into_bytes().to_vec() #3
}
Provides a small sending example that creates an HMAC tag from a key and message. section 3.2
Listing 3.2 Receiving an authenticated message in Rust
use sha2::Sha256;
use hmac::{Hmac, Mac, NewMac};
fn receive_message(key: &[u8], message: &[u8],
authentication_tag: &[u8]) -> bool {
let mut mac = Hmac::<Sha256>::new(key); #1
mac.update(message); #2
mac.verify(&authentication_tag).is_ok()
}
Provides the matching receiving example that recomputes and verifies an HMAC authentication tag. section 3.2



