Skip to content

Latest commit

 

History

236 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

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);

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

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 — TxState (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()
Loading

Receiver — byte-level ParseState

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)
Loading

Receiver display / watchdog — RxState

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
Loading

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.

About

Self-Healing Hardware and Software Complex for Encrypted Data Transmission

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages