SH2SC-EDT
Self-Healing Hardware and Software Complex for Encrypted Data Transmission
Loading...
Searching...
No Matches
SH2SC-EDT

en English | uk Українська

Self-Healing Hardware and Software Complex for Encrypted Data Transmission


Abstract

SH2SC-EDT is a fault-tolerant, cryptographically secured communication complex built on two Arduino Nano (ATmega328P) microcontrollers. It implements a custom transport/session-layer protocol — C2P-ARQ (ChaCha20-Poly1305 Automatic Repeat reQuest) — that provides authenticated encryption (ChaCha20-Poly1305 AEAD), guaranteed packet delivery via Stop-and-Wait ARQ, and a full three-phase session lifecycle (SYN / DAT / FIN).

The defining property of the complex is Self-Healing: upon link disruption, the transmitter node preserves its position in the data stream and autonomously re-establishes the session from the exact point of failure without operator intervention and without data loss. All logic on both nodes is implemented as non-blocking Finite State Machines running at 100% real-time in SimulIDE. Dynamic memory allocation is architecturally prohibited; the entire firmware operates within the 2 KB SRAM budget of the ATmega328P.


Core Features

  • Authenticated Encryption (AEAD): ChaCha20 stream cipher with a truncated 8-byte Poly1305 MAC per packet. No packet is acted upon before MAC verification passes memcmp.
  • Full Session Lifecycle: Three-phase C2P-ARQ session — FLAG_SYN handshake (nonce delivery), FLAG_DAT data transfer (Stop-and-Wait ARQ), FLAG_FIN teardown (authenticated session close).
  • Per-Packet Nonce Derivation: Unique IV per packet derived locally from the session nonce via XOR with the 16-bit sequence number across bytes [10..11]. The IV is never transmitted.
  • Stop-and-Wait ARQ: Every DataPacket requires an explicit ACK_BYTE (0x06). On NACK_BYTE (0x15) or timeout, the transmitter retransmits the identical ciphertext with the same seqNum. Retry limit: MAX_RETRIES = 50, timeout window: ACK_TIMEOUT_MS = 50 ms.
  • Self-Healing (Auto-Resume): On retry exhaustion, suspendSession() erases the session nonce from RAM, preserves melodyIndex, and enters TxState::RECONNECTING. A fresh HelloPacket is broadcast every RECONNECT_INTERVAL_MS = 2000 ms until the link is restored. Transmission resumes from the preserved index with zero data loss.
  • Dynamic Smart Watchdog (RX): The receiver session timeout adapts after each authenticated packet: current_timeout_limit = durationMs + NETWORK_GRACE_PERIOD_MS (3000 ms). Absorbs the worst-case retry storm (50 x 50 ms = 2500 ms) without false session teardown.
  • FSM-First Architecture: All TX and RX logic is driven exclusively by enum class state machines. No blocking delay() calls exist in the main loop. All timers use millis() deltas.
  • Hardware CSPRNG: Session nonce generated by a ChaCha20-based CSPRNG seeded with 256 bits of hardware entropy (ring oscillator, uninitialised SRAM, on-die ADC, TCNT1, white-noise ADC).

Protocol Specification: C2P-ARQ

Wire Format

All frames are preceded by a two-byte sync preamble (0xAA 0x55). The flags byte uses bitmask matching (&), providing noise resilience against single-bit errors.

HelloPacket — 15 bytes on wire

Field Size Value Description
SYNC1 1 byte 0xAA Preamble byte 1
SYNC2 1 byte 0x55 Preamble byte 2
flags 1 byte FLAG_SYN = 0x01 Session open identifier
nonce[12] 12 bytes CSPRNG 96-bit IETF ChaCha20 session nonce

DataPacket (FLAG_DAT / FLAG_FIN) — 17 bytes on wire

Field Size Value Description
SYNC1 1 byte 0xAA Preamble byte 1
SYNC2 1 byte 0x55 Preamble byte 2
flags 1 byte 0x02 / 0x04 FLAG_DAT or FLAG_FINAAD, not encrypted
seq_num 2 bytes uint16_t LE Packet sequence number — AAD, not encrypted
payload[4] 4 bytes ChaCha20 ciphertext Encrypted uint16_t note_index + uint16_t duration_ms
mac[8] 8 bytes Poly1305 truncated First 8 bytes of the full 16-byte Poly1305 tag

The 3-byte AAD (flags + seq_lo + seq_hi) is authenticated but not encrypted. Any bit-flip in these fields causes MAC verification to fail.

For FLAG_FIN packets, payload is encrypted zeros. The RX pipeline must call decrypt() into a discardBuf before computeTag() to advance the Poly1305 accumulator correctly; skipping decrypt() produces an incorrect expected tag and results in a false NACK.

ARQ Parameters

Constant Value Description
ACK_TIMEOUT_MS 50 ms Maximum wait for ACK before retransmission
MAX_RETRIES 50 Consecutive retransmissions before suspendSession()
RECONNECT_INTERVAL_MS 2000 ms HelloPacket broadcast interval in RECONNECTING state
NETWORK_GRACE_PERIOD_MS 3000 ms Added to note duration for Dynamic Watchdog timeout
BAUD_RATE 9600 UART speed (8N1)

FIFO Drain (Stale Buffer Prevention)

drainRxFifo() is called on TX before every sendHelloPacket(), sendPacket(), and sendFinPacket(). It discards all bytes in the 64-byte hardware UART RX FIFO, preventing stale NACKs accumulated during a noise burst from poisoning the response to the next packet.

On RX, resetParser() performs the symmetric operation after every MAC failure or parser timeout, draining the FIFO and resetting the byte-level FSM to WAIT_AA.


Security Model

Authenticated Encryption Pipeline

Both nodes use the ChaChaPoly library (Rhys Weatherley, Arduino Crypto). The pipeline per packet is identical on TX and RX:

flowchart LR A([clear]) --> B([setKey
MASTER_PSK, 32]) B --> C([setIV
packetNonce, 12]) C --> D([addAuthData
aad, 3 bytes]) D --> E([encrypt / decrypt
payload, 4 bytes]) E --> F([computeTag
mac, 16 bytes]) F --> G{"memcmp
mac[0..7]"} G -->|match| H([ACK
process data]) G -->|mismatch| I([NACK
resetParser])

Only the first 8 bytes of the 16-byte Poly1305 tag are transmitted (TRUNCATED_MAC_SIZE = 8). Verification uses memcmp(expectedMac, pkt->mac, 8). Tag truncation is a deliberate trade-off between wire overhead and security margin, acceptable for a 16-bit AVR channel.

Replay Attack Resistance

The per-packet IV is derived without transmission:

uint8_t packetNonce[12];
memcpy(packetNonce, s_sessionNonce, 12);
packetNonce[10] ^= (uint8_t)((seqNum >> 8u) & 0xFF);
packetNonce[11] ^= (uint8_t)(seqNum & 0xFF);
static uint16_t seqNum
Packet sequence number (0–65535, wraps).
static uint8_t s_sessionNonce[HELLO_NONCE_SIZE]
96-bit session nonce generated once per button press by sendHelloPacket().

All 65,536 seqNum values produce a distinct IV within a session. A new s_sessionNonce is generated by CSPRNG on every button press or RECONNECTING attempt, rendering cross-session replay attacks computationally infeasible.

Secure Key Material Destruction

MASTER_PSK is compiled into both nodes and never transmitted. s_sessionNonce is the only runtime secret and is zeroed at every session boundary:

memset(s_sessionNonce, 0x00, HELLO_NONCE_SIZE); // HELLO_NONCE_SIZE = 12
const uint8_t HELLO_NONCE_SIZE
ChaCha20 IV length in bytes (IETF 96-bit nonce format).
Definition protocol.h:54

This call is made unconditionally in four locations:

Location Trigger
TX suspendSession() MAX_RETRIES exhausted in any WAITING_* state
TX WAITING_FIN_ACK success FLAG_FIN acknowledged by RX
RX processFinPacket() MAC OK Authenticated session close
RX Dynamic Watchdog timeout TX disappeared without sending FLAG_FIN

Key material is never logged to Serial, LCD, or any output channel.


FSM State Reference

Transmitter — <tt>TxState</tt> (9 states)

stateDiagram-v2 [*] --> IDLE IDLE --> SENDING_HELLO : button press SENDING_HELLO --> WAITING_HELLO_ACK : HelloPacket sent WAITING_HELLO_ACK --> SENDING : ACK received WAITING_HELLO_ACK --> RECONNECTING : NACK / timeout × MAX_RETRIES\nsuspendSession() SENDING --> WAITING_ACK : DataPacket sent WAITING_ACK --> WAIT_BETWEEN_NOTES : ACK received WAITING_ACK --> RECONNECTING : NACK / timeout × MAX_RETRIES\nsuspendSession() RECONNECTING --> SENDING_HELLO : HelloPacket ACK received\n(auto-reconnect every 2 s) WAIT_BETWEEN_NOTES --> SENDING : gap elapsed, notes remain WAIT_BETWEEN_NOTES --> SENDING_FIN : all notes sent SENDING_FIN --> WAITING_FIN_ACK : FinPacket sent WAITING_FIN_ACK --> IDLE : ACK received\nmemset(s_sessionNonce) WAITING_FIN_ACK --> RECONNECTING : NACK / timeout × MAX_RETRIES\nsuspendSession()

Receiver — byte-level <tt>ParseState</tt>

stateDiagram-v2 [*] --> WAIT_AA WAIT_AA --> WAIT_55 : byte == 0xAA WAIT_AA --> WAIT_AA : byte != 0xAA WAIT_55 --> READ_TYPE : byte == 0x55 WAIT_55 --> WAIT_AA : byte != 0x55 READ_TYPE --> READ_PAYLOAD : flags byte read\n(FLAG_SYN / FLAG_DAT / FLAG_FIN) READ_TYPE --> WAIT_AA : invalid byte READ_PAYLOAD --> WAIT_AA : MAC OK → ACK, process packet READ_PAYLOAD --> WAIT_AA : MAC FAIL → resetParser() + NACK\n(drains UART FIFO)

Receiver display / watchdog — <tt>RxState</tt>

stateDiagram-v2 [*] --> WAITING_SYNC_1 WAITING_SYNC_1 --> WAITING_SYNC_2 : byte = 0xAA WAITING_SYNC_2 --> WAITING_FOR_TYPE : byte = 0x55 WAITING_SYNC_2 --> WAITING_SYNC_1 : byte ≠ 0x55 WAITING_FOR_TYPE --> READING_HELLO : FLAG_SYN (0x01) WAITING_FOR_TYPE --> READING_DATA : FLAG_DAT / FLAG_FIN READING_HELLO --> GOT_HELLO : nonce[12] complete READING_DATA --> GOT_DATA : payload[4] + mac[8] complete GOT_HELLO --> WAITING_SYNC_1 : processHelloBody() · ACK · Watchdog armed (5 s) GOT_DATA --> EXECUTING_ACTION : MAC pass GOT_DATA --> WAITING_SYNC_1 : MAC fail · NACK · resetParser() EXECUTING_ACTION --> WAITING_SYNC_1 : ACK · startNote() · Watchdog = durationMs + 3 s state "Dynamic Watchdog timeout\nmemset(s_sessionNonce)\ns_sessionActive = false" as WDT WAITING_FOR_TYPE --> WDT READING_DATA --> WDT EXECUTING_ACTION --> WDT WDT --> WAITING_SYNC_1


Hardware and Environment

Target Hardware

Component Specification
Microcontrollers 2x Arduino Nano (ATmega328P, 16 MHz, 2 KB SRAM, 32 KB Flash)
Displays 2x Aip31068 I2C LCD 16x2, address 0x3E, pins A4/A5
Buzzer 1x Piezo speaker on PWM pin 9 (Node B only)
CSPRNG source Hardware ring oscillator on INT0 (pin 2, both nodes)
Noise injector XOR gate + Pulse Generator (1 kHz, 15%) + AND gate + Switch
Monitoring Multi-channel oscilloscope, Time/Div ~200 us

Required Libraries

Library Purpose Source
Arduino Cryptography Library (Crypto) ChaCha20-Poly1305 AEAD Rhys Weatherley
LiquidCrystal_AIP31068 I2C LCD driver for Aip31068 controller Andriy Golovnya

Build Environment

  • Arduino IDE 2.x with AVR board support package.
  • SimulIDE 1.1.0 (or later) for circuit simulation and real-time validation.
  • Compiler: avr-g++ with C++11 (-std=gnu++11).

Repository Structure

sh2sc-edt/
|
+-- TransmitterNode/
| +-- TransmitterNode.ino Entry point: setup(), loop(), button debounce
| +-- transmitter.h TxState FSM, sendHelloPacket(), sendPacket(),
| | sendFinPacket(), suspendSession(), drainRxFifo()
| +-- protocol.h Shared structs (HelloPacket, DataPacket), flag
| | constants, MASTER_PSK, timing constants
| +-- csprng.h ChaCha20-based CSPRNG, hardware entropy pool,
| | 64-byte keystream cache
| +-- melody.h PROGMEM melody arrays (note indices, durations)
|
+-- ReceiverNode/
| +-- ReceiverNode.ino Entry point: setup(), loop(), note timer, watchdog
| +-- receiver.h RxState FSM, processReceivedByte(), ParseState,
| | authenticateAndPlay(), processFinPacket(),
| | resetParser(), Dynamic Watchdog
| +-- protocol.h Shared structs and constants (identical to TX)
| +-- csprng.h CSPRNG (RX variant, no button entropy source)
|
+-- docs/
| +-- main.qd Quarkdown technical documentation source
|
+-- shsc-arq.sim1 SimulIDE circuit file (primary simulation)
+-- README.md This file

Key Constants Reference

Constant Value Defined in Description
FLAG_SYN 0x01 protocol.h Session open frame flag
FLAG_DAT 0x02 protocol.h Data frame flag
FLAG_FIN 0x04 protocol.h Session close frame flag
ACK_BYTE 0x06 protocol.h Positive acknowledgement
NACK_BYTE 0x15 protocol.h Negative acknowledgement
SYNC_BYTE_1 0xAA protocol.h Frame preamble byte 1
SYNC_BYTE_2 0x55 protocol.h Frame preamble byte 2
HELLO_NONCE_SIZE 12 protocol.h ChaCha20 IETF nonce length (bytes)
TRUNCATED_MAC_SIZE 8 protocol.h Transmitted Poly1305 tag length
DATA_PAYLOAD_SIZE 4 protocol.h Encrypted payload length (bytes)
REST_INDEX 255 protocol.h Sentinel index for silence/pause
NOTE_DICT_SIZE 21 receiver.h Size of universal frequency table
MAX_RETRIES 50 protocol.h ARQ retransmission limit
ACK_TIMEOUT_MS 50 protocol.h ACK wait window (ms)
RECONNECT_INTERVAL_MS 2000 transmitter.h HelloPacket broadcast interval
NETWORK_GRACE_PERIOD_MS 3000 receiver.h Watchdog grace period added to note duration

Academic Context

Developed as project for the discipline **"Computer Systems Architecture"**. The system demonstrates that a resource-constrained 8-bit AVR microcontroller can implement industry-grade cryptographic authentication (AEAD), a stateful session protocol, and application-layer fault recovery within a 2 KB SRAM budget. The SimulIDE noise injector (XOR gate + 1 kHz pulse generator) provides reproducible channel corruption for validating all five fault-tolerance scenarios: single-burst corruption, sustained jamming (Self-Healing proof), stale FIFO poisoning, Dynamic Watchdog teardown, and FLAG_FIN corruption under noise.