Airgapexchange: Zero-Communication Key Exchange
Air-gapped X25519 + Ed25519 key exchange via QR-printable XorIDA threshold shares delivered by independent physical couriers. Zero electronic communication between parties. Mathematically impossible to intercept remotely. Bootstrap secure channels in hostile environments where all electronic paths are compromised, monitored, or unavailable.
Executive Summary
Airgapexchange solves the bootstrapping problem for secure communications in environments where electronic channels cannot be trusted: diplomatic missions, military deployments, intelligence operations, critical infrastructure, and high-value negotiations.
Traditional key exchange protocols require an electronic channel. Diffie-Hellman, X25519 ECDH, ML-KEM key encapsulation — all assume you can send bytes over the network. When the network itself is the threat, these protocols fail.
Airgapexchange uses XorIDA threshold sharing to split X25519 public keys and Ed25519 signing keys into K-of-N QR-printable shares. Each share is Base45-encoded and wrapped in an Xformat envelope for tamper detection. Print each share as a physical QR code and hand it to a different courier. The couriers travel independently — different routes, different timing, different modes of transport.
The recipient scans any K shares, reconstructs the sender's public keys, performs X25519 ECDH to derive a shared secret, and establishes a secure channel. An attacker who compromises fewer than K couriers learns nothing about the keys — not computationally hard to break, but mathematically impossible.
Once the shared secret is established, parties can communicate via encrypted channels using the derived key. Airgapexchange is the secure bootstrap. The ongoing conversation happens via Xlink, email with XorIDA split-channel, or any authenticated encryption scheme.
The Problem
Key exchange protocols require electronic communication channels. In hostile environments, all electronic channels may be compromised, monitored, or unavailable. There is no standard protocol for bootstrapping secure communications when the network itself is the adversary.
Why Traditional Approaches Fail
Diffie-Hellman requires an electronic channel. Classic DH, ECDH (X25519), and post-quantum KEMs (ML-KEM-768) all assume you can exchange public keys over a network. If nation-state adversaries control the network, they intercept, manipulate, or block the exchange. A man-in-the-middle substitutes their own keys. You establish a "secure" channel with the attacker, not your intended counterparty.
Pre-shared keys don't scale. Manually distributing symmetric keys to every pair of communicating parties is logistically infeasible. A single stolen USB drive or photographed key sheet exposes the entire communication channel. No forward secrecy, no fault tolerance.
Trust-on-first-use (TOFU) fails under active attack. SSH, Signal, and WhatsApp use TOFU: "Trust this key the first time you see it." If the first exchange is compromised, you trust the attacker's key forever. No out-of-band verification, no second chance.
Single courier is a single point of failure. Handing one courier a full key creates a catastrophic risk. Coercion, bribery, interception, or a simple traffic accident means total compromise. No redundancy, no threshold protection.
Real-World Scenarios
Embassy-to-HQ secure channel. A diplomatic mission in a hostile country needs to establish encrypted communications with the home office. The local internet is state-controlled. Certificate authorities cannot be trusted. A compromised VPN endpoint means full traffic visibility to adversaries. Electronic key exchange is not an option.
Military forward operating base. A field unit deploys to a contested region with no secure communications infrastructure. Satellite links may be jammed or intercepted. Radio frequencies are monitored. The unit needs to establish command-and-control channels without electronic exposure during initialization.
Intelligence dead drop alternative. Traditional physical dead drops have a single point of failure: one compromised location exposes the entire operation. Threshold-protected key exchange distributes the risk across multiple independent couriers, each carrying insufficient information to compromise the channel.
Critical infrastructure network segmentation. A nuclear facility, power grid control center, or water treatment plant requires cryptographic isolation between operational technology (OT) networks and external systems. Air-gapped key exchange establishes secure channels without any electronic path that could be exploited during the initialization phase.
Solution Architecture
Airgapexchange combines XorIDA threshold secret sharing, QR code transport, and X25519 ECDH to enable secure key exchange with zero electronic communication during the bootstrap phase.
Core Components
Protocol Overview
Alice wants to establish a secure channel with Bob. They cannot trust any electronic communication during the bootstrap phase. Alice generates an X25519 keypair and an Ed25519 signing keypair. She keeps the private keys. She takes the two public keys (32 bytes each), concatenates them with her DID, and uses prepareExchange() to split the payload into K-of-N QR shares.
Each share is a Base45-encoded Xformat envelope containing one XorIDA share of the public key bundle. Alice prints each share as a QR code on separate pieces of paper. She hands each QR code to a different courier: Share 1 via diplomatic pouch, Share 2 via trusted traveler, Share 3 via commercial courier service. The couriers travel independently.
Bob receives the QR codes as they arrive. When he has scanned K shares, he calls completeExchange(qrShares, bobPrivateKey). The function reconstructs Alice's public keys, verifies HMAC integrity, extracts her DID, and performs X25519 ECDH using Bob's private key and Alice's reconstructed public key. The output is a 32-byte shared secret.
Alice and Bob now share a cryptographic secret that was never transmitted electronically. They can use this shared secret as an AES-256-GCM key, an HMAC key, or input to HKDF for deriving session keys. The secure channel is bootstrapped.
Real-World Use Cases
Six scenarios where electronic key exchange is impossible or unacceptable.
Diplomatic missions in hostile countries cannot trust local network infrastructure. Couriers carry QR shares via diplomatic pouch (share 1), trusted attaché (share 2), and commercial flight (share 3). 2-of-3 threshold ensures channel bootstrap even if one courier is delayed or compromised.
2-of-3 threshold, diplomatic pouch deliveryMilitary units deploying to contested regions with no secure communications infrastructure. Shares delivered via different transport modes: air drop (share 1), ground convoy (share 2), supply helicopter (share 3). Couriers never carry enough information to compromise the channel.
3-of-5 threshold, multi-transport deliveryIntelligence officers and confidential sources establish secure channels without electronic exposure. Shares delivered via dead drop (share 1), trusted intermediary (share 2), postal service (share 3). Threshold protection means a single compromised drop reveals nothing.
2-of-3 threshold, dead drop deliveryNuclear facilities, power grids, and water treatment plants require cryptographic isolation between operational technology networks and external systems. Air-gapped key exchange establishes secure channels without any electronic path exploitable during initialization.
2-of-2 threshold, hand delivery onlyHigh-stakes merger negotiations, legal settlements, and corporate transactions require cryptographically secure channels without exposing intent via monitored electronic communications. Couriers deliver shares via separate law firms, investment banks, and commercial services.
2-of-3 threshold, legal courier deliverySatellite ground stations in multiple countries establish secure channels for telemetry and command data. Electronic key exchange exposes critical infrastructure to interception. Physical QR shares delivered via trusted personnel to each ground station. 3-of-5 threshold tolerates compromised stations.
3-of-5 threshold, international deliveryTechnical Architecture
Four-layer architecture: key generation, threshold splitting, envelope serialization, and QR transport.
Protocol Flow
Step 1: Key Generation (Sender)
Alice generates an X25519 keypair for key agreement and an Ed25519 keypair for signing. She exports the public keys as raw 32-byte Uint8Arrays. She constructs an ExchangeKeys object containing her X25519 public key, Ed25519 signing public key, and DID.
const aliceKeys: ExchangeKeys = { publicKey: aliceX25519PublicKey, // Uint8Array, 32 bytes signingPublicKey: aliceEd25519PubKey, // Uint8Array, 32 bytes did: 'did:key:z6Mk...', };
Step 2: Threshold Splitting (Sender)
Alice calls prepareExchange(aliceKeys, config) with a configuration specifying N total shares, K threshold, and optional courier count. The function serializes the public keys + DID into a binary payload, applies PKCS#7 padding, splits via XorIDA, generates HMAC-SHA256 for each share, wraps each share in an Xformat envelope with product type XMEET (0x19), and Base45-encodes the envelope for QR printing.
const config: ExchangeConfig = { n: 3, // total shares k: 2, // threshold to reconstruct courierCount: 3, // independent couriers (>= n) label: 'HQ-to-Embassy key exchange 2026-Q1', }; const result = await prepareExchange(aliceKeys, config); if (!result.ok) throw new Error(result.error); // Hand each share.qrData to a different courier as a printed QR code for (const share of result.value.shares) { console.log(`Share ${share.shareId}: ${share.qrData}`); }
Step 3: Physical Transport
Alice prints each share.qrData string as a QR code. She hands each printed QR code to a different courier. The couriers travel independently via different routes, different timing, different modes of transport. No electronic communication occurs between Alice and Bob during this phase.
Step 4: Share Collection (Recipient)
Bob scans arriving QR codes using any standard QR scanner (camera app, dedicated scanner, etc.). He collects the Base45-encoded strings in an array. He does not need all N shares — only K shares are required.
Step 5: Reconstruction and ECDH (Recipient)
Bob calls completeExchange(qrShares, bobX25519PrivateKey). The function Base45-decodes each QR string, deserializes the Xformat envelope, verifies the product type is XMEET, checks HMAC-SHA256 integrity, reconstructs the public key bundle via XorIDA, unpads PKCS#7, deserializes the payload, extracts Alice's X25519 public key and Ed25519 signing public key, and performs X25519 ECDH using Bob's private key and Alice's reconstructed public key to derive a 32-byte shared secret.
const scannedQrCodes: string[] = [couriers[0].qrData, couriers[1].qrData]; const completed = await completeExchange(scannedQrCodes, bobX25519PrivateKey); if (!completed.ok) throw new Error(completed.error); console.log(completed.value.peerDid); // Alice's DID console.log(completed.value.sharedSecret); // 32-byte X25519 ECDH shared secret
Step 6: Secure Channel Bootstrap
Alice and Bob now share a cryptographic secret. They can use this shared secret directly as an AES-256-GCM key, pass it to HKDF-SHA256 to derive multiple session keys, or use it as input to any key derivation function. The secure channel is established.
Security Model
Threshold Security: Fewer than K couriers cannot reconstruct either party's public key. XorIDA threshold sharing is information-theoretically secure — no amount of computational power can recover the key from K-1 shares. An attacker must compromise K or more couriers to learn anything about the keys.
HMAC Integrity: Each share includes an HMAC-SHA256 tag computed over the share data. The tag is verified before reconstruction. Tampered shares are detected and rejected immediately. A single corrupted or manipulated share fails HMAC verification and prevents reconstruction, forcing the attacker to deliver valid shares or be detected.
Courier Independence: Shares are delivered via independent couriers using different routes, different timing, and different modes of transport. A single compromised courier reveals nothing. A single delayed courier does not block the exchange (as long as K shares arrive). Courier independence is enforced by the sender — Alice chooses N >= K couriers and ensures they do not coordinate or communicate.
No Electronic Exposure: The public keys never transit an electronic channel during the bootstrap phase. An adversary monitoring all electronic communications learns zero bits about the keys. Network interception, TLS MITM, compromised CAs, DNS poisoning, and BGP hijacking are all irrelevant during the air-gapped exchange.
Forward Secrecy: Once the shared secret is established, parties can use ephemeral X25519 keypairs for each session (via Xlink or another ECDH-based protocol). Compromise of the air-gapped bootstrap keys does not compromise past or future sessions if ephemeral keys are used correctly.
Integration Guide
Install, generate keys, split shares, print QR codes, scan shares, reconstruct keys, derive shared secret.
Installation
npm install @private.me/airgapexchange
Sender Flow (Alice)
import { prepareExchange } from '@private.me/airgapexchange'; import type { ExchangeKeys, ExchangeConfig } from '@private.me/airgapexchange'; // 1. Generate X25519 + Ed25519 keypairs (Web Crypto API) const x25519KeyPair = await crypto.subtle.generateKey( { name: 'ECDH', namedCurve: 'X25519' }, true, ['deriveKey', 'deriveBits'] ); const ed25519KeyPair = await crypto.subtle.generateKey( { name: 'Ed25519' }, true, ['sign', 'verify'] ); // 2. Export public keys as raw bytes const x25519PubBytes = new Uint8Array( await crypto.subtle.exportKey('raw', x25519KeyPair.publicKey) ); const ed25519PubBytes = new Uint8Array( await crypto.subtle.exportKey('raw', ed25519KeyPair.publicKey) ); // 3. Prepare exchange configuration const aliceKeys: ExchangeKeys = { publicKey: x25519PubBytes, signingPublicKey: ed25519PubBytes, did: 'did:key:z6Mk...', }; const config: ExchangeConfig = { n: 3, k: 2, courierCount: 3, label: 'Alice-to-Bob 2026-Q1', }; // 4. Split into QR shares const result = await prepareExchange(aliceKeys, config); if (!result.ok) { console.error('Exchange prep failed:', result.error); throw new Error(result.error); } // 5. Print each share as a QR code result.value.shares.forEach((share, idx) => { console.log(`Share ${idx + 1} QR data:`, share.qrData); // Use a QR code library to generate printable QR images // Hand each printed QR to a different courier });
Recipient Flow (Bob)
import { completeExchange } from '@private.me/airgapexchange'; // 1. Scan QR codes from arriving couriers const scannedQrCodes: string[] = [ 'QR1_BASE45_STRING...', // from courier 1 'QR2_BASE45_STRING...', // from courier 2 ]; // 2. Bob's X25519 private key (pre-generated) const bobX25519PrivateKey: CryptoKey = ...; // from Web Crypto API // 3. Reconstruct Alice's keys and derive shared secret const completed = await completeExchange(scannedQrCodes, bobX25519PrivateKey); if (!completed.ok) { console.error('Exchange completion failed:', completed.error); throw new Error(completed.error); } // 4. Use the shared secret const { peerPublicKey, peerSigningPublicKey, peerDid, sharedSecret } = completed.value; console.log('Peer DID:', peerDid); console.log('Shared secret (32 bytes):', sharedSecret); // sharedSecret can now be used for AES-256-GCM, HMAC, or HKDF input
Bidirectional Exchange
For a full bidirectional secure channel, both Alice and Bob execute the sender flow and the recipient flow. Alice sends QR shares of her public keys to Bob. Bob sends QR shares of his public keys to Alice. Each party scans K shares from the other party and derives the same shared secret via ECDH. Once both sides have the shared secret, they can encrypt messages using AES-256-GCM or establish Xlink agent-to-agent channels.
Performance Benchmarks
Airgapexchange performance is dominated by physical courier transit time, not computation time. Cryptographic operations complete in milliseconds.
Computational Benchmarks
Key generation: X25519 + Ed25519 keypair generation via Web Crypto API takes ~2ms on modern hardware. This is a one-time operation per party.
Share preparation: Splitting 64 bytes (two 32-byte public keys) into 2-of-3 shares via XorIDA + HMAC + Xformat + Base45 encoding takes ~5ms. Most of this time is HMAC-SHA256 computation and Base45 encoding.
Share reconstruction: Decoding 2 QR shares, verifying HMAC, reconstructing via XorIDA, and performing X25519 ECDH takes ~3ms. HMAC verification dominates this operation.
QR code size: Each share is ~150 bytes of Base45-encoded data. This fits comfortably in a QR code Version 3 (29x29 modules) with error correction level M (15% damage tolerance). Printing and scanning are sub-second operations with modern devices.
Real-World Timing
Cryptographic operations are negligible compared to physical courier transit time. A typical air-gapped exchange takes hours to days depending on courier routes:
- Local delivery (same city): 2-4 hours for all K couriers to arrive
- International delivery (different countries): 24-72 hours depending on courier mode (air vs ground)
- High-security delivery (diplomatic pouch): 1-7 days depending on routing and security protocols
The computational overhead is effectively zero relative to physical transit time. Choose courier count and threshold based on security requirements and acceptable delivery latency, not cryptographic performance.
Honest Limitations
Airgapexchange is not a replacement for traditional key exchange protocols. It is a bootstrapping mechanism for hostile environments where electronic channels cannot be trusted.
What Airgapexchange Does NOT Solve
Courier compromise. If an adversary can intercept, coerce, or bribe K or more couriers, the exchange is compromised. Choose K and N based on your threat model. For high-threat environments, use 3-of-5 or 4-of-7 to tolerate multiple courier failures.
Bidirectional bootstrap latency. A full bidirectional secure channel requires both parties to send QR shares to each other. This doubles the courier transit time. If Alice needs 24 hours for her couriers to reach Bob, and Bob needs 24 hours for his couriers to reach Alice, the total bootstrap time is 48 hours (assuming parallel courier dispatch).
No authentication of couriers. Airgapexchange does not provide cryptographic proof that a courier is legitimate. The sender must choose trusted couriers and verify their identity through out-of-band means. A substituted courier carrying a valid-looking QR code can deliver a share that passes HMAC verification but belongs to an attacker's key exchange.
No protection against QR forgery. An attacker who compromises K couriers can substitute their own QR codes. HMAC verification only proves that the share matches the other shares in the group — it does not prove the shares represent the intended sender's keys. Combine airgapexchange with out-of-band key fingerprint verification (e.g., Alice reads her Ed25519 public key fingerprint to Bob over a trusted voice channel).
Ongoing communication requires a separate protocol. Airgapexchange establishes a shared secret. It does not provide message encryption, replay protection, or forward secrecy for ongoing communications. Use Xlink, Signal Protocol, or another authenticated encryption scheme for actual message exchange after the bootstrap.
No revocation or key rotation. Once the shared secret is established, there is no built-in mechanism to revoke or rotate keys. If a key is compromised, parties must execute a new air-gapped exchange to establish a fresh shared secret. For long-lived channels, use ephemeral X25519 keypairs for each session (via Xlink) to provide forward secrecy independent of the bootstrap keys.
• All electronic channels are monitored or compromised
• Physical courier delivery is feasible and acceptable
• Bootstrap latency (hours to days) is acceptable
• Threshold protection against courier compromise is required
Do NOT use airgapexchange when:
• Electronic key exchange is trusted (use X25519 ECDH directly)
• Real-time bootstrap is required (use TOFU or pre-shared keys)
• Physical courier delivery is not feasible
• Single courier is acceptable (use encrypted USB or other transport)
For Integration Engineers
Error handling, API reference, deployment patterns for production air-gapped key exchange systems.
Error Handling
All errors use colon-separated sub-codes for detailed diagnostics. Base codes are stable; sub-codes provide context.
Error Categories
| Category | Example Codes | When |
|---|---|---|
| Configuration | INVALID_CONFIG:N_TOO_SMALL, K_EXCEEDS_N | prepareExchange() validation failures |
| Keys | INVALID_KEYS:PUBLIC_KEY_LENGTH, MISSING_DID | ExchangeKeys validation failures |
| Cryptography | SPLIT_FAILED, HMAC_FAILED, ECDH_FAILED | XorIDA, HMAC, or X25519 operations fail |
| Reconstruction | RECONSTRUCT_FAILED:HMAC_MISMATCH, INSUFFICIENT_SHARES | completeExchange() failures |
| Format | RECONSTRUCT_FAILED:INVALID_ENVELOPE, PRODUCT_MISMATCH | Base45 decode or Xformat validation failures |
Complete Error Reference
| Code | Sub-Code | Meaning |
|---|---|---|
| INVALID_CONFIG | N_TOO_SMALL | n must be >= 2 |
| INVALID_CONFIG | K_TOO_SMALL | k must be >= 2 |
| INVALID_CONFIG | K_EXCEEDS_N | k cannot exceed n |
| INVALID_CONFIG | COURIER_COUNT_TOO_LOW | courierCount must be >= n |
| INVALID_KEYS | PUBLIC_KEY_LENGTH | X25519 public key must be exactly 32 bytes |
| INVALID_KEYS | SIGNING_KEY_LENGTH | Ed25519 signing key must be exactly 32 bytes |
| INVALID_KEYS | MISSING_DID | DID string is required |
| SPLIT_FAILED | (none) | XorIDA split or envelope serialization failed |
| HMAC_FAILED | (none) | HMAC generation failed |
| RECONSTRUCT_FAILED | HMAC_MISMATCH | Share integrity check failed -- data may be tampered |
| RECONSTRUCT_FAILED | INSUFFICIENT_SHARES | Fewer than k shares provided |
| RECONSTRUCT_FAILED | DESERIALIZE | Payload deserialization failed |
| RECONSTRUCT_FAILED | INVALID_ENVELOPE | Base45 or Xformat envelope is malformed |
| RECONSTRUCT_FAILED | PRODUCT_MISMATCH | Envelope product type is not XMEET |
| RECONSTRUCT_FAILED | UUID_MISMATCH | Shares belong to different exchanges |
| RECONSTRUCT_FAILED | UNPAD | PKCS#7 unpadding failed |
| ECDH_FAILED | KEY_DERIVATION | X25519 ECDH derivation failed |
| SIGNATURE_INVALID | (none) | Ed25519 signature verification failed |
| DUPLICATE_SHARE | (none) | Two or more shares have the same index |
const result = await prepareExchange(aliceKeys, config); if (!result.ok) { const { code, message, hint } = result.error; if (code.startsWith('INVALID_CONFIG')) { console.error('Configuration error:', message); console.log('Hint:', hint); // Fix n/k parameters and retry } else if (code.startsWith('INVALID_KEYS')) { console.error('Key validation failed:', message); // Regenerate keys with correct lengths } else { console.error('Unexpected error:', code, message); } throw new Error(message); }
Full API Surface
Complete function signatures and type definitions.
prepareExchange
Split an X25519 public key into K-of-N QR-printable shares for air-gapped delivery. Returns an ExchangeResult with an array of shares, each containing a Base45-encoded QR string.
completeExchange
Reconstruct a counterparty's public key from scanned QR shares and optionally derive an ECDH shared secret. If no private key is provided, returns 32 zero bytes as sharedSecret placeholder.
Type Definitions
interface ExchangeKeys { publicKey: Uint8Array; // X25519 public key, 32 bytes signingPublicKey: Uint8Array; // Ed25519 signing public key, 32 bytes did: string; // DID identifier label?: string; // Optional human-readable label } interface ExchangeConfig { n: number; // Total shares (2-255) k: number; // Threshold to reconstruct (2-n) courierCount?: number; // Number of independent couriers (default: n) label?: string; // Optional label for this exchange } interface ExchangeResult { exchangeId: string; // UUID identifying this exchange shares: ExchangeShare[]; // Array of n QR-printable shares ownerDid: string; // DID of the key owner preparedAt: string; // ISO 8601 timestamp } interface ExchangeShare { shareId: number; // 1-based share index qrData: string; // Base45-encoded Xformat envelope courier?: string; // Optional courier identifier } interface ExchangeCompleteResult { exchangeId: string; // UUID of the exchange peerPublicKey: Uint8Array; // Reconstructed X25519 public key (32B) peerSigningPublicKey: Uint8Array; // Reconstructed Ed25519 signing key (32B) peerDid: string; // DID of the other party sharedSecret: Uint8Array; // X25519 ECDH shared secret (32B), or zeroes if no private key completedAt: string; // ISO 8601 timestamp } interface ExchangeError { code: string; // Machine-readable error code with optional sub-code message: string; // Human-readable description hint?: string; // Actionable suggestion for fixing the error }
Package Deployment
Install and integrate airgapexchange into your application for air-gapped key exchange.
NPM Installation
# Configure private npm registry npm config set @private.me:registry https://private.me/npm/ # Install airgapexchange npm install @private.me/airgapexchange # Or with pnpm pnpm add @private.me/airgapexchange # Or with yarn yarn add @private.me/airgapexchange
TypeScript Integration
import { prepareExchange, completeExchange, type ExchangeKeys, type ExchangeConfig } from '@private.me/airgapexchange'; // 1. Prepare exchange with your keys const keys: ExchangeKeys = { publicKey: x25519PublicKey, // 32-byte X25519 public key signingPublicKey: ed25519PublicKey, // 32-byte Ed25519 signing key did: 'did:key:z6Mk...', label: 'Alice Workstation' }; const config: ExchangeConfig = { n: 3, // Generate 3 shares k: 2, // Require 2 to reconstruct label: 'Diplomatic Key Exchange' }; const result = await prepareExchange(keys, config); if (!result.ok) { console.error('Exchange preparation failed:', result.error); return; } // 2. Print QR codes and send via couriers result.value.shares.forEach(share => { printQRCode(share.qrData, share.shareId); }); // 3. On the receiving side, scan QR codes and complete exchange const scannedQRs = [qr1Data, qr2Data]; // From QR scanner const completed = await completeExchange(scannedQRs, bobPrivateKey); if (completed.ok) { // Use the shared secret for secure communication const { sharedSecret, peerDid } = completed.value; initializeSecureChannel(sharedSecret, peerDid); }
Environment Requirements
- Node.js 18+ or modern browser with Web Crypto API support
- TypeScript 5.0+ recommended (types included)
- Dependencies: @private.me/crypto (XorIDA), @private.me/shareformat (Xformat)
- QR code library: Use qrcode or similar for QR generation/scanning
Production Checklist
- Test QR quality: Verify QR codes scan reliably at intended print DPI (300+ recommended)
- Courier independence: Ensure K couriers cannot coordinate or communicate
- Physical security: Use tamper-evident envelopes or diplomatic pouches
- Fingerprint verification: Verify peer key fingerprints over out-of-band channel
- Audit logging: Log all exchange preparation and completion events
- Key lifecycle: Plan for key rotation and compromise recovery
Integration with Xlink
Once the air-gapped exchange completes, use the established trust to bootstrap Xlink agent-to-agent communication. The peer's public keys can be imported into Xlink's trust registry for ongoing encrypted messaging with replay protection and forward secrecy.
import { Agent } from '@private.me/agent-sdk'; import { completeExchange } from '@private.me/airgapexchange'; // Complete air-gapped exchange const completed = await completeExchange(qrShares, privateKey); if (!completed.ok) throw new Error(completed.error); // Register peer in Xlink trust registry const agent = await Agent.create({ registry, transport }); await registry.register({ did: completed.value.peerDid, publicKey: completed.value.peerPublicKey, signingPublicKey: completed.value.peerSigningPublicKey, scopes: ['xlink:send', 'xlink:receive'], }); // Send encrypted Xlink envelope await agent.send({ to: completed.value.peerDid, payload: { message: 'Secure channel established' }, scope: 'xlink:send', });
Operational Deployment
Production operational patterns for air-gapped key exchange systems.
Courier Selection
Independence: Choose couriers who do not coordinate or communicate. Use different organizations, different modes of transport, different routes. For 2-of-3, consider: diplomatic pouch (courier 1), commercial air freight (courier 2), trusted traveler (courier 3).
Trusted identity: Verify courier identity through out-of-band means before handing over QR codes. Use physical credentials, biometric verification, or pre-arranged recognition signals. A substituted courier carrying valid QR codes is indistinguishable from a legitimate courier without additional verification.
Redundancy: For high-value exchanges, use N > K to tolerate courier delays or failures. 3-of-5 means the exchange completes even if 2 couriers are delayed, compromised, or fail to arrive.
QR Code Handling
Print quality: Use high-DPI printers (300 DPI minimum) to ensure QR codes are scannable. Test scan reliability with multiple devices before handing to couriers. Include error correction level M (15% damage tolerance) or Q (25%) for physical resilience.
Physical security: Print QR codes on tamper-evident paper if available. Seal in opaque envelopes to prevent visual inspection during transit. For diplomatic contexts, use official pouch seals.
Destruction after use: Once the recipient scans K shares and completes the exchange, destroy all printed QR codes via shredding or incineration. Do not leave physical artifacts that could be recovered later.
Operational Security
Key fingerprint verification: After completing the exchange, verify the peer's Ed25519 signing public key fingerprint over a trusted out-of-band channel (e.g., voice call, in-person meeting). This prevents substitution attacks where all K couriers are compromised and deliver an attacker's QR codes.
Audit logging: Log all exchange preparation and completion events with timestamps, exchange IDs, and peer DIDs. Store logs separately from cryptographic keys. Use append-only tamper-evident logs for compliance contexts.
Key lifecycle: Treat air-gapped bootstrap keys as long-lived identity keys. Use ephemeral X25519 keypairs for each message session (via Xlink) to provide forward secrecy independent of the bootstrap keys. If bootstrap keys are compromised, execute a fresh air-gapped exchange to re-establish trust.