Cryptography overhaul for V2 #1450
Draft
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
My pet project outgrew itself, so I thought I share it here, maybe someone will have use for the information and stuff I learned along the way in the future.
MeshCore v2 Encryption: ChaCha20-Poly1305 Implementation
Requirements
This implementation requires repeaters to forward PAYLOAD_VER_2 packets! (currently in dev everything is dropped above VER_1)
Decisions
I decided to use ChaCha20-Poly1305 because we are using software for decrypt anyway (ESP's can do hardware accelerated stuff, but I tried to be universal, chacha is 10x faster than the current AES-ECB+HMAC anyway, it was designed for "low-end" systems like our embedded variants)
I decided to use 12 byte nonce and 12 byte tag because it's the lowest that adheres to standards. (Nonce can be lowered to 8 to save some minor airtime)
Draft PR, if anyone have anything to teach me more I'd be glad to hear it.
TL;DR
ChaCha20-Poly1305 authenticated encryption, replacing AES-128-ECB scheme for enhanced security.
The implementation maintains backward compatibility with v1 packets while providing stronger cryptographic guarantees for "v2-capable" nodes, as minimal airtime increase as I could squeeze out, no handshakes no nothing "additional" packets.
This was a huge project, I worked on it in "one section at a time" to preserve context windows and try to understand everything I did along the way.
I'm not a crypto expert nor a coding guru, so read everything with this in mind.
I've tested everything I could on my daily driver companion and my repeater (the code is still running on them, I'm using our mesh with this right now, of course v2 encryptes talk just between my repeater's admin commands and my other test companion).
And for the masochist people, the full changelog, I "enchanced" my scribbles with claude:
What Changed
Core Cryptographic Changes
New Encryption Algorithm: ChaCha20-Poly1305 AEAD cipher
Payload Version System
PAYLOAD_VER_1: Legacy AES-128-ECB (unchanged, remains default)PAYLOAD_VER_2: New ChaCha20-Poly1305 encryptionADV_FEAT1_CHACHA_CAPABLE)Channel Tagging
CHANNEL_FLAG_V2toGroupChannel.flagsbytePacket Types Migrated to v2
PAYLOAD_TYPE_REQ(request packets)PAYLOAD_TYPE_RESPONSE(response packets)PAYLOAD_TYPE_TXT_MSG(text messages)PAYLOAD_TYPE_GRP_TXT(group text messages)PAYLOAD_TYPE_GRP_DATA(group data messages)PAYLOAD_TYPE_PATH(path return packets)PAYLOAD_TYPE_ANON_REQ(anonymous request packets)Forwarding Logic Updated
PAYLOAD_VER_2packets (previously dropped)Security Hardening (Additional Fixes)
This PR also includes critical security hardening fixes identified during code audit:
Packet Parsing Hardening (
Packet::readFrom())uint8_ttouint16_tto prevent truncationACK Packet Parsing
payload_len >= 4validation before readingack_crcTRACE Packet Parsing
payload_len >= 9) before reading trace fieldsBridge Compatibility
RS232BridgeandESPNowBridgenow compatible withuint16_tlength parameterDesign Decisions in full
Why ChaCha20-Poly1305?
Why 12-Byte (96-bit) Authentication Tag?
rweather/Cryptolibrary supports tag truncation viaCHACHA_TAG_SIZEWhy 12-Byte Nonce?
rweather/Cryptolibrary expectationsUtils::getHardwareRandom()AAD (Additional Authenticated Data) Implementation
AAD protects packet metadata from tampering:
dest_hash,src_hash(orchannel_hash),payload_type,payload_versionHow It Works
Encryption Flow (v2)
peerSupportsCHACHA()orCHANNEL_FLAG_V2)Utils::getHardwareRandom()(platform-specific RNG)Utils::encryptCHACHA()which:[nonce (12)] [ciphertext] [tag (12)]PAYLOAD_VER_2in headerDecryption Flow (v2)
PAYLOAD_VER_2from packet headerUtils::decryptCHACHA()which:secure_compare())Capability Negotiation
ADV_FEAT1_CHACHA_CAPABLEflag inPAYLOAD_TYPE_ADVERTpacketsContactInfo.supports_chachaandClientInfo.supports_chachatrack peer capabilitiesAirtime Comparison (sorry if the table is shifted)
Packet Size Overhead
Airtime (BW62.5, SF8, CR8)
Security Improvements
What v2 Provides
secure_compare()to prevent timing attacksWhat v2 Doesn't Change
PAYLOAD_TYPE_ACKpackets remain unencrypted (by design, for low overhead)Backward Compatibility
Resource Usage (CPU/RAM)
RAM Impact
CPU Impact
Known Limitations / Future Work
Breaking Changes
PAYLOAD_VER_2packets