---
title: digest.hmac_md5
summary: null
url: >-
  https://www.fastly.com/documentation/reference/vcl/functions/cryptographic/digest-hmac-md5
---

```
STRING digest.hmac_md5(STRING key, STRING s)
```

**Available in:** all subroutines

Returns the HMAC-MD5 of `message` using `key`, as a lowercase hexadecimal string with a `0x` prefix.

## Parameters

| Parameter | Type   | Description                         |
| --------- | ------ | ----------------------------------- |
| `key`     | STRING | The secret key for HMAC computation |
| `message` | STRING | The message to authenticate         |

The `key` is used directly as the HMAC key. For keys longer than 64 bytes (the MD5 block size), the key is first hashed with MD5 before use, as specified in RFC 2104.

## Return value

Returns a 34-character string: a `0x` prefix followed by 32 lowercase hexadecimal characters representing the 128-bit (16-byte) HMAC.

Example output: `0x36b89aaa72560638852703acba484b2b`

If `key` is empty or not set, the function returns an empty string (not set).

## Security

Unlike plain MD5, no practical attack breaks HMAC-MD5 as an authenticator. However, it is no longer recommended and should only be used when required for compatibility with legacy systems that cannot be upgraded.

The 128-bit output of HMAC-MD5 provides only 64 bits of security against forgery attacks (due to birthday bound considerations). Modern security standards require at least 128 bits of security, which HMAC-SHA256 provides.

## Examples

### Basic usage

```vcl
declare local var.hmac STRING;
set var.hmac = digest.hmac_md5("secret-key", "hello world");
# Result: 0x36b89aaa72560638852703acba484b2b
```

To verify this output using OpenSSL:

```term
$ echo -n "hello world" | openssl dgst -md5 -hmac "secret-key"
MD5(stdin)= 36b89aaa72560638852703acba484b2b
```

### RFC 2104 test vector

```vcl
declare local var.hmac STRING;
set var.hmac = digest.hmac_md5("key", "The quick brown fox jumps over the lazy dog");
# Result: 0x80070713463e7749b90c2dc24911e275
```

## Security considerations

### Use SHA-256 for new applications

For any new integration, use `digest.hmac_sha256()`:

```vcl
# Recommended
set var.signature = digest.hmac_sha256(var.key, var.message);

# NOT recommended - only for legacy compatibility
set var.legacy_signature = digest.hmac_md5(var.key, var.message);
```

### Constant-time comparison

When comparing HMAC values for authentication, always use `digest.secure_is_equal()` to prevent timing attacks. String comparison with `==` leaks information about which bytes matched, potentially allowing an attacker to forge valid authentication tags:

```vcl
if (!digest.secure_is_equal(var.expected, var.actual)) {
    error 401 "Invalid signature";
}
```

## Related content

- `digest.hmac_md5_base64()` - Returns Base64-encoded output instead of hex.
- `digest.hmac_sha256()` - HMAC with SHA-256 (recommended for new code).
- `digest.hmac_sha512()` - HMAC with SHA-512.
- `digest.secure_is_equal()` - Constant-time string comparison.
