MeshCore Encryption Overview
MeshCore Encryption Overview
MeshCore employs a two-tier cryptographic model: channel traffic uses AES-256-CTR with a key derived from the channel name, while direct messages use ECDH to derive a per-pair shared secret. Understanding this distinction is essential for security-sensitive deployments.
Channel Traffic: AES-256-CTR
All traffic broadcast to a channel is encrypted with AES-256 in Counter (CTR) mode. CTR mode was chosen for several practical reasons specific to the LoRa radio environment:
- No padding requirement. CTR mode turns a block cipher into a stream cipher, so payloads of arbitrary length are encrypted without padding overhead critical on a constrained 255-byte LoRa payload.
- Random access decryption. Any block of the ciphertext can be decrypted independently once the counter value is known, which simplifies partial-packet handling.
- Error isolation. A corrupted bit in the ciphertext corrupts only the corresponding plaintext bit; unlike CBC mode, there is no error propagation across block boundaries.
Key Derivation from Channel Name
The AES key for channel traffic is derived by hashing the UTF-8 encoded channel name with SHA-256 to produce 32 bytes of key material used directly as the AES-256 key. The counter nonce is constructed from the sender address and packet sequence number fields already present in the MeshCore packet header, ensuring counter uniqueness without a separate nonce field in the frame.
Changing a channel encryption key requires renaming the channel and redistributing the new name to all participants. There is no separate key rotation mechanism independent of the channel identity.
Direct Messages: ECDH Key Exchange
One-to-one direct messages use Elliptic Curve Diffie-Hellman (ECDH) to derive a per-pair shared secret. Each MeshCore node generates a static Curve25519 keypair at first boot. The public half is included in the node periodic advertisement packets, which flood the mesh so that every other node learns every reachable node public key.
When node A sends a private message to node B, it performs a Curve25519 scalar multiplication using its own private key and B advertised public key. Node B performs the same operation using its own private key and A public key. Both operations converge on the same shared secret without that secret ever appearing on the radio medium. This shared secret is passed through a KDF to produce the AES-256 session key for the message.
Why ECDH Provides Forward Secrecy That Meshtastic PSK Does Not
Meshtastic uses a static Pre-Shared Key (PSK) configured identically on every channel node. If an adversary later obtains the PSK through device seizure, firmware dump, or social engineering, they can retrospectively decrypt every recorded message. This is the classic forward secrecy failure mode.
MeshCore ECDH for direct messages provides a stronger property: each pair of nodes derives a unique shared secret from their respective static keypairs. An attacker capturing raw radio traffic cannot derive the shared secret without possessing at least one node private key. Private keys never leave the device.
Note: MeshCore does not implement ephemeral ECDH (ECDHE). Keypairs are static rather than generated fresh per session. If a node private key is extracted from flash, past direct messages could be decrypted by an attacker who also has peer private keys. True per-session forward secrecy is not present in the current design. The improvement over static PSK is nonetheless significant in practice.
Public Key Announcement in Advertisements
MeshCore nodes periodically broadcast advertisement packets containing display name, hardware capabilities, and a 32-byte Curve25519 public key. These advertisements are flooded across the mesh so that within a few advertisement cycles every reachable node has a copy of every other node public key in its local key store. No prior direct contact is required before a secure direct message can be sent.
Private Key Storage on Device
The private key is generated once at first boot and written to non-volatile storage (NVS on ESP32, equivalent flash on nRF52). There is no mechanism in standard MeshCore firmware to export or display a node private key through the CLI or BLE interface. ESP32 devices have no dedicated hardware security element; the NVS partition is readable by anyone with physical flash access on devices without flash encryption enabled. Treat physical device access as a key-compromise event.
What an Attacker Can and Cannot Determine from Raw LoRa Captures
| Observable from raw LoRa capture | Not determinable from raw LoRa capture |
|---|---|
| That radio traffic is occurring | Message plaintext in direct messages |
| Approximate transmitter location via RSSI triangulation | Message plaintext on channel if channel name is unknown |
| Transmission frequency, spreading factor, bandwidth | Node identities beyond the 4-byte address in the header |
| Packet header fields: sender/destination address, packet type, hop count | Private keys of any node |
| Node public keys from advertisement floods | ECDH shared secrets derived from private and public key pairs |
| Approximate network topology from routing advertisements | Channel AES keys if the channel name is not known |
| Traffic volume, timing, and communication graph | Direct message content even with both public keys in hand |
Traffic analysis remains possible regardless of encryption strength. Operational security on a mesh radio network must account for this inherent metadata visibility.