A secure, air-gapped Bitcoin signing system that communicates via sound.
This project implements a true air-gap for cryptographically signing messages using the Bitcoin ECDSA algorithm. It consists of two independent Python scripts that communicate with each other not over a network, but through ultrasonic audio signals, much like an old-school acoustic modem.
This ensures that the private key, which is held on the offline computer, is never exposed to any network, providing a high level of security against remote attacks.
The system is composed of two distinct components:
-
Computer A: The Online Terminal (
online_terminal.py)- Has internet access.
- Has a microphone and speakers.
- Does NOT hold any private keys.
- Role: Fetches data from a web source, transmits it via sound to the offline signer, receives a signature back via sound, and posts the signature to a web destination.
-
Computer B: The Offline Singer (
offline_signer.py)- Has NO internet access (air-gapped).
- Has a microphone and speakers.
- Role: Securely stores a Bitcoin private key. It listens for messages, validates them, signs them, and transmits the signature back via sound.
[ Internet ] <--> [ Computer A ] <--( Ultrasonic Sound )--> [ Computer B ]
(Web API) (Online Terminal) (Offline Singer)
Data is transmitted between the two computers using a custom acoustic protocol based on Frequency-Shift Keying (FSK).
-
Frequencies: All communication happens in the ultrasonic range (17-22 kHz) to minimize audible noise and interference.
- Data Bit '0': 21,000 Hz
- Data Bit '1': 22,000 Hz
- Start Signal: 19,000 Hz (signals the beginning of a data frame)
- End Signal: 20,000 Hz (signals the end of a data frame)
- ACK (Acknowledge): 17,000 Hz (confirms successful receipt)
- NACK (Negative-Acknowledge): 18,000 Hz (indicates corrupt data)
-
Data Frame Structure: Every message (payload) is sent within a structured frame:
- Start Tone: A brief tone at
START_FREQ. - Payload: The core data (e.g., the message to sign or the signature itself), converted to a stream of bits.
- Checksum: A 2-byte (16-bit) CRC16-XMODEM checksum calculated from the payload bytes. This is appended to the payload bits.
- End Tone: A brief tone at
END_FREQ.
- Start Tone: A brief tone at
-
Automated Handshake (ACK/NACK): The system uses a fully automated, closed-loop handshake to ensure data integrity:
- A -> B (Message): Terminal sends the message frame.
- B -> A (Status): Singer validates the checksum. Sends
ACKtone if valid,NACKtone if corrupt. - A's Action: If
ACKis received, it proceeds. IfNACKor timeout, it automatically re-transmits the message. - B -> A (Signature): Once the message is acknowledged, the Singer sends the signature frame.
- A -> B (Status): Terminal validates the checksum. Sends
ACKif valid,NACKif corrupt. - B's Action: If
ACKis received, the process is complete. IfNACKor timeout, it automatically re-transmits the signature.
This loop continues until data is successfully transferred in both directions.
This project is a functional proof-of-concept. It could be extended in several ways:
- More Robust Error Correction: Implement a forward error correction (FEC) algorithm to not just detect, but also correct minor bit-flip errors, reducing the need for re-transmission.
- Increased Bandwidth: Experiment with more advanced modulation schemes like Phase-Shift Keying (PSK) or Quadrature Amplitude Modulation (QAM) to increase the data transfer rate.
- Dynamic Frequency Adaptation: The program could analyze ambient noise at the start and select the quietest frequency bands for communication.
- GUI: Build a simple graphical user interface for both the online and offline terminals to make the system more user-friendly.