> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/cis/practical-4-message-authentication-codes-mac-using-hmac.md).

# Practical 4 — Message Authentication Codes (MAC) using HMAC

### Aim

To implement a Message Authentication Code (MAC) using HMAC-SHA256 in Python, to verify the integrity and authenticity of a message using a shared secret key.

### Concept

A **Message Authentication Code (MAC)** is a short piece of information attached to a message that allows the receiver to verify both:

* **Integrity** — the message was not altered in transit.
* **Authenticity** — the message genuinely came from someone who possesses the shared secret key.

A plain hash function alone (e.g. just `SHA-256(message)`) cannot provide authenticity, because anyone can compute a hash of any message — there's nothing secret involved. A MAC solves this by mixing a **shared secret key** into the hashing process, so only someone who knows the key can generate a valid MAC for a given message.

**HMAC (Hash-based Message Authentication Code)** is the most widely used way to build a MAC out of a hash function. It uses **symmetric** cryptography — unlike RSA digital signatures (asymmetric, using a public/private key pair), HMAC requires both the sender and receiver to already share the exact same secret key.

#### How it works, step by step

1. Sender and receiver agree on a secret key in advance (shared securely beforehand, not sent with the message).
2. The sender computes `HMAC(key, message)` using a chosen hash function (SHA-256 here) — this produces the MAC.
3. The sender sends the message along with this MAC value.
4. The receiver independently recomputes `HMAC(key, message)` on the message they received, using the same secret key.
5. The receiver compares their freshly computed MAC to the one that was sent.
6. If they match → the message is authentic and unaltered. If they don't match → the message was tampered with, or wasn't produced using the correct key.

### Mathematical Formula

HMAC is formally defined as:

```
HMAC(K, m) = H( (K' ⊕ opad) ‖ H( (K' ⊕ ipad) ‖ m ) )
```

Where:

* `H` = the underlying hash function (SHA-256 in this practical)
* `K` = the secret key
* `K'` = the key `K`, padded with zero-bytes to match the hash function's internal block size (or first hashed down if `K` is longer than the block size)
* `m` = the message
* `ipad` = the "inner padding" constant — the byte `0x36` repeated to fill one block
* `opad` = the "outer padding" constant — the byte `0x5c` repeated to fill one block
* `⊕` = bitwise XOR
* `‖` = concatenation

In plain terms: the key is combined with the message and hashed once (the "inner hash"), then that result is combined with the key again (differently) and hashed a second time (the "outer hash"). This nested, two-pass structure is what protects HMAC from certain length-extension attacks that a naive `H(key + message)` construction would be vulnerable to. Python's `hmac` module implements this entire formula internally — the code below just calls it.

### Python Code

```python
import hmac
import hashlib

secret_key = b'super_secret_key_123'
message = b'ABC'

mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print("Original Message: ", message.decode())
print("Generated HMAC-SHA256:", mac)

received_mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()

if hmac.compare_digest(mac, received_mac):
  print("Message is Authentic and Integrity is preserved!")
else:
  print("Message was tampered with!")
```

### Line-by-Line Explanation

```python
import hmac
```

Imports Python's built-in `hmac` module. This gives access to `hmac.new()` (to build the MAC) and `hmac.compare_digest()` (to safely compare two MAC values).

```python
import hashlib
```

Imports the `hashlib` module, which provides the actual underlying hash algorithm implementations — here, `hashlib.sha256` is passed into `hmac.new()` to tell it which hash function to use internally.

```python
secret_key = b'super_secret_key_123'
```

Defines the shared secret key as a **bytes** object (the `b'...'` prefix creates a bytes literal, not a regular string). Both the sender and receiver must already know this exact key beforehand — it is never transmitted alongside the message.

```python
message = b'ABC'
```

Defines the message to authenticate, also as bytes, since `hmac.new()` requires byte-string input rather than a plain `str`.

```python
mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
```

This is the core MAC-generation step:

* `hmac.new(secret_key, message, hashlib.sha256)` creates an HMAC object initialized with the secret key, the message, and SHA-256 as the hash function.
* `.hexdigest()` converts the resulting binary HMAC output into a human-readable hexadecimal string.
* The result is stored in `mac` — this is the value the sender would attach to and send along with the message.

```python
print("Original Message: ", message.decode())
```

Prints the original message. `.decode()` converts the `bytes` object back into a normal, readable `str` (bytes objects would otherwise print with a `b'...'` prefix).

```python
print("Generated HMAC-SHA256:", mac)
```

Prints the generated MAC (already a hex string from `.hexdigest()`, so no `.decode()` is needed here).

```python
received_mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
```

Simulates the receiver's side: using the same secret key and the same hash algorithm, this independently recomputes the MAC over the message. In a real scenario, this would be computed on whatever message bytes actually arrived over the network — here, it's recomputed on the same `message` variable to keep the demonstration simple (i.e. simulating an untampered message arriving correctly).

```python
if hmac.compare_digest(mac, received_mac):
```

Compares the originally generated `mac` to the `received_mac` that was just recomputed.

* `hmac.compare_digest()` is used instead of a plain `==` because it performs the comparison in **constant time** — it doesn't return early as soon as it finds the first mismatched character. This guards against **timing attacks**, where an attacker could otherwise infer a valid MAC byte-by-byte by measuring how long a naive `==` comparison takes to fail.

```python
  print("Message is Authentic and Integrity is preserved!")
```

If the two MACs matched exactly, this confirms the message is both authentic (came from someone with the correct secret key) and unaltered.

```python
else:
  print("Message was tampered with!")
```

If the MACs didn't match, this warns that the message may have been modified, or wasn't produced using the correct shared key.

### Sample Output

```
Original Message:  ABC
Generated HMAC-SHA256: <64-character hex string>
Message is Authentic and Integrity is preserved!
```

### HMAC vs RSA Digital Signature (Quick Comparison)

|                   | HMAC (MAC)                                                                         | RSA Digital Signature                                                        |
| ----------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Cryptography type | Symmetric (shared secret key)                                                      | Asymmetric (public/private key pair)                                         |
| Key requirement   | Both parties must already know the same secret key                                 | Only the sender needs the private key; anyone can verify with the public key |
| Speed             | Very fast                                                                          | Slower (relies on modular exponentiation)                                    |
| Non-repudiation   | No — since the key is shared, either party could technically have produced the tag | Yes — only the private key holder could have signed it                       |

### Conclusion

This practical demonstrates how a Message Authentication Code, built using HMAC-SHA256, allows a receiver to confirm both the integrity and authenticity of a message using a pre-shared secret key — a fast, symmetric alternative to RSA digital signatures.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/cis/practical-4-message-authentication-codes-mac-using-hmac.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
