|
SH2SC-EDT
Self-Healing Hardware and Software Complex for Encrypted Data Transmission
|
Self-Healing Hardware and Software Complex for Encrypted Data Transmission
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.
memcmp.FLAG_SYN handshake (nonce delivery), FLAG_DAT data transfer (Stop-and-Wait ARQ), FLAG_FIN teardown (authenticated session close).[10..11]. The IV is never transmitted.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.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.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.enum class state machines. No blocking delay() calls exist in the main loop. All timers use millis() deltas.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.
| 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 |
| 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_FIN — AAD, 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.
| 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) |
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.
Both nodes use the ChaChaPoly library (Rhys Weatherley, Arduino Crypto). The pipeline per packet is identical on TX and RX:
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.
The per-packet IV is derived without transmission:
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.
MASTER_PSK is compiled into both nodes and never transmitted. s_sessionNonce is the only runtime secret and is zeroed at every session boundary:
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.
| 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 |
| Library | Purpose | Source |
|---|---|---|
Arduino Cryptography Library (Crypto) | ChaCha20-Poly1305 AEAD | Rhys Weatherley |
LiquidCrystal_AIP31068 | I2C LCD driver for Aip31068 controller | Andriy Golovnya |
avr-g++ with C++11 (-std=gnu++11).| 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 |
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.