Module 3/5 · Weeks 7–9 · 27 h

Secure C2 links

UAT 367 Cybersecurity, Command and Control Links and Unmanned Aircraft Systems Traffic Management

About 90 minDraft, awaiting reviewLast updated 27 September 2026

Lesson

By the end of this module you will be able to

  1. Explain the structure of MAVLink 2 signatures and the replay protection rules
  2. Create and verify MAVLink 2 frame signatures with SHA-256
  3. Distinguish authentication from encryption and use DTLS/TLS and AES-GCM correctly
  4. Design a dual-path C2 and assess its availability

Prerequisites: UAT 367 Modules 1–2 · UAT 105 Module 5 (HMAC)

Why this matters

The C2 (command and control) link carries commands to the drone and status back. UAT 312 covered designing a link with enough signal and procedures for when it is lost. This module asks the next question: how does the drone know a command really came from its pilot? Without authentication, anyone with a radio on the same frequency who knows the protocol can send a land or reroute command. In Module 1’s threat model this threat scored 15, high risk.

The MAVLink guide specifies that a signed frame sets the first incompat flag (0x01) and appends a 13-byte signature block:

  • Link ID, 1 byte, separating paths such as radio and LTE.
  • Timestamp, 6 bytes, in units of 10 microseconds since 1 January 2015 GMT.
  • Signature, 6 bytes: the first 48 bits of SHA-256 over the 32-byte secret key followed by the header, payload, CRC, link ID and timestamp.
A bar showing a signed MAVLink 2 frame from left to right: header 10 bytes, payload 0 to 255 bytes, CRC 2 bytes, link ID 1 byte, timestamp 6 bytes and signature 6 bytes. A bracket under the last three parts reads 13-byte signature block
Figure 1 Layout of a signed MAVLink 2 frame

Replay protection rules from the guide: the timestamp must be greater than that of the previous message on the same stream (system ID, component ID, link ID), and a message whose timestamp is more than 1 minute behind the receiver’s time must be rejected. Without these rules, an attacker could record a valid land command and resend it later. For unsigned messages, the system decides which types to accept, such as RADIO_STATUS from its own radio; all others should be rejected. The guide also warns that the key must never appear in parameters or logs.

Example 1 Signing and verifying a HEARTBEAT frame

The key is derived from a sample phrase for teaching only; a real key must come from a secure random source.

import hashlib
import struct

def crc_x25(data, crc=0xFFFF):
    for b in data:
        tmp = b ^ (crc & 0xFF)
        tmp = (tmp ^ (tmp << 4)) & 0xFF
        crc = ((crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4)) & 0xFFFF
    return crc

KEY = hashlib.sha256(b"lesson-demo-passphrase").digest()   # 32 bytes, for teaching only
HEARTBEAT = struct.pack("<IBBBBB", 0, 2, 3, 0x81, 4, 3)     # custom_mode, type, autopilot, base_mode, status, version

def sign(seq, payload, ts, link_id=0, sysid=1, compid=1, msgid=0, crc_extra=50):
    hdr = bytes([0xFD, len(payload), 0x01, 0x00, seq, sysid, compid]) + msgid.to_bytes(3, "little")
    crc = crc_x25(hdr[1:] + payload + bytes([crc_extra]))
    tail = struct.pack("<H", crc) + bytes([link_id]) + ts.to_bytes(6, "little")
    return hdr + payload + tail + hashlib.sha256(KEY + hdr + payload + tail).digest()[:6]

last_ts = {}
def verify(frame, now):
    body, sig = frame[:-6], frame[-6:]
    if hashlib.sha256(KEY + body).digest()[:6] != sig:
        return "reject: bad signature"
    ts = int.from_bytes(body[-6:], "little")
    stream = (body[5], body[6], body[-7])                    # system ID, component ID, link ID
    if stream in last_ts and ts <= last_ts[stream]:
        return "reject: replayed or out-of-order timestamp"
    if ts < now - 6_000_000:                                 # 1 minute = 6,000,000 units of 10 µs
        return "reject: older than 1 minute"
    last_ts[stream] = ts
    return "accept"

now = 123_456_839
f1 = sign(7, HEARTBEAT, 123_456_789)
print(f"frame {len(f1)} bytes: {f1.hex()}")
print("first delivery   ->", verify(f1, now))
print("same frame again ->", verify(f1, now))
tampered = bytearray(sign(8, HEARTBEAT, 123_456_800))
tampered[13] ^= 0x01                                         # flip 1 payload bit
print("tampered payload ->", verify(bytes(tampered), now))
print("old frame, link 1->", verify(sign(9, HEARTBEAT, now - 7_000_000, link_id=1), now))
frame 34 bytes: fd0901000701010000000000000002038104033bac0015cd5b070000c82d318a978f
first delivery   -> accept
same frame again -> reject: replayed or out-of-order timestamp
tampered payload -> reject: bad signature
old frame, link 1-> reject: older than 1 minute

The frame is 10 + 9 + 2 + 13 = 34 bytes. The instructor checked that these bytes match the frame pymavlink 2.4.50 produces with the same key, timestamp and sequence. Changing a single payload bit breaks the signature, and the same frame sent again is rejected because its timestamp does not increase.

Authentication is not encryption

MAVLink signing provides authentication and integrity, but the content is still readable. Anyone who intercepts the signal sees the drone’s position and status. Data that must stay confidential, such as video or parcel data, needs encryption as well.

  • On IP networks such as LTE, use DTLS 1.3 (RFC 9147) over UDP or TLS 1.3 (RFC 8446) over TCP, which both encrypt and authenticate.
  • If you design at packet level yourself, use a mode that both encrypts and authenticates, such as AES-GCM per NIST SP 800-38D, which warns that reusing an IV with the same key even once can open the door to forgeries, a requirement almost as important as keeping the key secret.
  • Key management decides who generates keys, how they are distributed, where they are stored, when they are rotated and how they are revoked when a device is lost. It goes wrong more often than the algorithms do.

Dual-path C2

Using radio and LTE together raises availability, but watch for common-mode failures, such as a power cut at the control centre that takes out both paths at once. RTCA DO-362 sets minimum performance for terrestrial C2, and DO-400 gives guidance on lost-C2 procedures, which are still needed even with two paths.

The aircraft on the left, the GCS at top right and a C2 server at bottom centre. Two-way blue arrows between aircraft and GCS read C2 radio, signed. A purple arrow from the aircraft to the C2 server reads LTE and DTLS 1.3, then from the server to the GCS reads TLS 1.3. Gold boxes labelled key sit at the aircraft, GCS and server
Figure 2 Dual-path C2 architecture and key locations

Example 2 C2 availability

Availabilities are assumed values from route statistics; each flight lasts 30 minutes.

A_RADIO, A_LTE, P_COMMON = 0.97, 0.95, 0.002
FLIGHT_MIN = 30

options = {
    "radio only": A_RADIO,
    "radio + LTE (independent)": 1 - (1 - A_RADIO) * (1 - A_LTE),
    "radio + LTE with common mode": (1 - P_COMMON) * (1 - (1 - A_RADIO) * (1 - A_LTE)),
}
for name, a in options.items():
    print(f"{name:<30} availability {a:.4f}  expected outage {(1 - a) * FLIGHT_MIN * 60:5.1f} s per flight")
radio only                     availability 0.9700  expected outage  54.0 s per flight
radio + LTE (independent)      availability 0.9985  expected outage   2.7 s per flight
radio + LTE with common mode   availability 0.9965  expected outage   6.3 s per flight

The second path cuts link outage time sharply, but a common-mode failure of just 0.2% more than doubles the outage compared with the independent case. Power, network and location of the two paths must be separated as far as possible.

Module lab

Lab: enabling signing and testing in SITL

  1. Run the code from Example 1 and compare with the frame pymavlink produces using the same key and timestamp.
  2. Enable MAVLink signing in SITL following the ArduPilot or PX4 guide and the GCS software in use.
  3. Send commands from a script without the key, check that they are rejected and record the log.
  4. Replay a recorded frame on loopback and check that replay protection works.
  5. Write a key management plan for the medical delivery network and compute availability with Example 2.

Common mistakes

Watch out

  • Thinking signing encrypts the data.
  • Accepting every unsigned message type for convenience.
  • Storing the key in parameters or logs.
  • Reusing an IV in AES-GCM.
  • Assuming two paths remove the need for lost-C2 procedures.

Summary

  • The MAVLink 2 signature block is 13 bytes; the signature is SHA-256 over a 32-byte key and the frame, truncated to 6 bytes.
  • Increasing timestamps per stream and the 1-minute limit protect against replay.
  • Signing authenticates but does not hide content; use DTLS/TLS or AES-GCM when confidentiality is needed.
  • Dual-path C2 raises availability, but common-mode failures must be reduced and lost-C2 procedures are still required.

Check your understanding

  1. What makes up the MAVLink 2 signature block, and how many bytes is it?
  2. How many MAVLink timestamp units are in 1 second?
  3. Why is a replayed frame rejected even though every byte is valid?
  4. Two independent paths each have availability 0.9. What is the combined availability?
  5. What can someone intercepting a signed radio link still see?
Answers
  1. Link ID 1 byte, timestamp 6 bytes and signature 6 bytes, 13 bytes in total.
  2. 100,000 units (10 µs each).
  3. Its timestamp is not greater than the latest timestamp on the same stream.
  4. All of the content, such as position and status, because signing does not encrypt.

Key formulas

MAVLink 2 signature
Availability of two paths

Key references

  1. MAVLink Development Team. Message signing (authentication). MAVLink developer guide. link
  2. Dworkin, M. (2007). Recommendation for block cipher modes of operation: Galois/Counter Mode (GCM) and GMAC (NIST SP 800-38D). National Institute of Standards and Technology. link
  3. Rescorla, E., Tschofenig, H., & Modadugu, N. (2022). The Datagram Transport Layer Security (DTLS) protocol version 1.3 (RFC 9147). RFC Editor. link
  4. Rescorla, E. (2018). The Transport Layer Security (TLS) protocol version 1.3 (RFC 8446). RFC Editor. link
  5. RTCA. (2016). Command and control (C2) data link minimum operational performance standards (MOPS) (terrestrial) (DO-362). link
  6. RTCA. (2023). Guidance material: Lost C2 link procedures (DO-400). link

Further reading

Study the assigned knowledge units in advance, review media and take the module quiz

In class / field

Intensive lab and field practice recorded in a lab notebook

Learning evidence: Lab notebook signed by the instructor

Module quiz

This is a formative self-check, not a graded exam

Knowledge domain: Communications, networks and IoT · Law, safety and risk