---
kind: concept
slug: message-authentication-code
title: Message authentication code (MAC)
summary: >-
  A short tag, made with a shared secret key, that lets the receiver check a message was not changed and came from a key holder. The only source here is the MAVLink survey: MAVLink 2 signing uses a 6-byte truncated SHA-256 tag, a 32-byte key and a timestamp check against replay. The paper names no keyed construction and contradicts itself on whether MAVLink authenticates.
tags: [security, authentication, integrity, communication-protocol]
papers: ["1906.10641"]
related: [cyclic-redundancy-check, intrusion-detection]
status: draft
updated_at: 2026-11-06
---

## Overview

A message authentication code is a tag computed from a message and a secret
key that sender and receiver share. The receiver recomputes the tag and
compares it with the one it received. A match shows that the message was not
changed and that the sender holds the key. The wiki has one source for this
concept, the MAVLink survey, so the description below is that paper's account
of its signing scheme [arxiv:1906.10641 §II.C.2].

The survey separates this from a checksum. A CRC catches accidental changes,
but the paper describes signing as the mechanism that provides authentication
[arxiv:1906.10641 §II.C.1] [arxiv:1906.10641 §II.C.2]. The two are different
tools, and [CRC](/concepts/cyclic-redundancy-check) does not replace a tag.

## Variants

### Truncated SHA-256 tag with a 32-byte key (MAVLink 2 packet signing)

The only variant in the wiki. Card:
[MAVLink in a Nutshell: A Survey](/papers/1906.10641).

- **Tag.** The tag is 6 bytes: the first six bytes of a SHA-256 value
  computed over the message and a timestamp, with a 32-byte shared secret key
  [arxiv:1906.10641 §II.C.2].
- **Construction not named.** The paper does not name a keyed construction,
  and it does not say how the key and the data are combined
  [arxiv:1906.10641 §II.C.2] [arxiv:1906.10641 §IV.B.1]. An implementation has
  to take the exact method from the protocol specification it targets.
- **Signature block.** A signed frame carries 13 bytes after the checksum:
  a link ID (1 byte), a timestamp (6 bytes) and the tag (6 bytes). The frame
  marks itself as signed in the incompatibility flags, bit value 0x01
  [arxiv:1906.10641 §II.C.2].
- **Replay check.** Each stream is keyed by system ID, component ID and link
  ID. The paper says a frame is dropped when its timestamp is older than the
  last one on its stream, or more than one minute away from the local clock.
  The timestamp counts 10-microsecond units since 1 January 2015 GMT
  [arxiv:1906.10641 §II.C.2].
- **Unsigned frames.** The paper leaves to the implementation whether to
  accept or reject them [arxiv:1906.10641 §II.C.2].
- **Reported cost.** The survey cites other work for about 26 microseconds of
  overhead per packet and 812 bytes of added firmware on an autopilot
  [arxiv:1906.10641 §IV.B.1]. The wiki has no second source for these figures,
  and they were not re-checked here.

## When to use which

The wiki has one variant, so the table compares situations the survey
addresses, not tags against each other.

| Situation | Use | Why |
|---|---|---|
| Peers speak MAVLink 2 and can share a key | Packet signing with the 13-byte block | The survey describes signing as the way to authenticate frames [arxiv:1906.10641 §II.C.2] |
| Peers speak MAVLink 1.0 | No tag: the signature block exists only in MAVLink 2 | The paper describes the block as part of the 2.0 frame [arxiv:1906.10641 §II.C.2] |
| Telemetry runs on a slow radio | Count the 13 bytes on each signed frame against the link rate | The block is added to every signed frame [arxiv:1906.10641 §II.C.2]; the radio rate is up to 250 kbps [arxiv:1906.10641 §II.B] |
| Commands must stay secret | Not covered here | The survey says MAVLink has no native encryption [arxiv:1906.10641 §III.B] |
| Old frames must not be replayed | Keep the timestamp check on | The per-stream timestamp rule is what the paper gives against replay [arxiv:1906.10641 §II.C.2] |
| Key distribution to ground station and drone | Not specified in this wiki | The paper gives the key size and use, not how keys are provisioned [arxiv:1906.10641 §II.C.2] |
| Only accidental corruption must be caught | A checksum, not a tag | See [CRC](/concepts/cyclic-redundancy-check) |

## Implementation sketch

Verify one signed frame: check the tag first, then the timestamp, and store
the timestamp only when both pass. The keyed digest is a placeholder because
the paper does not name the construction.

```pseudocode
# Accept or reject one signed MAVLink 2 frame  [arxiv:1906.10641 §II.C.2]
# Input:  frame_bytes (unsigned part of the frame), sys_id, comp_id,
#         link_id, timestamp (10 us units), tag (6 bytes), key (32 bytes),
#         last_seen (dict per stream), now (seconds since 2015-01-01 GMT)
# Output: True if accepted

def accept_signed(frame_bytes, sys_id, comp_id, link_id,
                  timestamp, tag, key, last_seen, now):
    # Keyed digest over message and timestamp; the combination is not
    # stated in the paper [arxiv:1906.10641 §II.C.2] [§IV.B.1]
    digest = keyed_sha256(key, frame_bytes, timestamp)
    # Only the first six bytes of the digest are sent  [§II.C.2]
    if digest[:6] != tag:
        return False
    # Streams are keyed by system, component and link  [§II.C.2]
    stream = (sys_id, comp_id, link_id)
    # Drop frames older than the newest one seen on this stream  [§II.C.2]
    if timestamp < last_seen.get(stream, 0):
        return False
    # Drop frames more than one minute from local time  [§II.C.2]
    if abs(now - timestamp_to_seconds(timestamp)) > 60:
        return False
    # Remember the newest timestamp for this stream  [§II.C.2]
    last_seen[stream] = timestamp
    return True
```

## Contradictions

The paper disagrees with itself on what MAVLink authenticates. Both sides, as
the survey states them:

- §III.B says MAVLink has no native encryption and only weak authentication,
  and §III.A says the same about the threat model
  [arxiv:1906.10641 §III.A] [arxiv:1906.10641 §III.B].
- §IV says the protocol implements neither encryption nor authentication
  [arxiv:1906.10641 §IV].
- §II.C.2 describes an optional signing mechanism that authenticates frames
  in MAVLink 2 [arxiv:1906.10641 §II.C.2].

The wiki does not resolve this. Reading all three together, the MAVLink 2
signing is optional, and the paper does not say whether it is common in
deployed systems.

The inputs to the signature also differ between sections. §II.C.2 names the
timestamp, the message and the key [arxiv:1906.10641 §II.C.2]. §IV.B.1 names
the secret key, payload, link ID, header, CRC and timestamp
[arxiv:1906.10641 §IV.B.1]. Table V lists the §IV.B.1 set in another order
[arxiv:1906.10641 tab. V]. The paper gives no order, so the sketch above
leaves it open.

## Papers

- [MAVLink in a Nutshell: A Survey](/papers/1906.10641): survey and tutorial of
  MAVLink 1.0 and 2.0, with the packet-signing scheme and the security
  discussion above. Reports no new experiments.
