QR Transfer Workflow

Air-gapped key share distribution via encrypted QR codes

Purpose

Show how key shares move between devices using QR codes. Air-gap capable: no internet required. Offline-first design for maximum security.

When QR Transfer Is Used

Phase 1: Encryption & Compression

On Device A (Exporter), the key share is prepared for QR encoding:

Share Binary Data ├─ Key Material (256 bits) ├─ Curve ID (1 byte) ├─ Metadata (timestamps, UUID) └─ Checksum (BLAKE3) ↓ Compress (zlib) ├─ Reduces size ~40% └─ Enables multi-part QR ↓ Encrypt (AES-256-GCM) ├─ Requires user passphrase ├─ Generates random nonce └─ Produces authenticated ciphertext

Technical details:

Phase 2: Binary Framing & QR Segmentation

Encrypted data is split into chunks (max 2953 bytes per QR code) and wrapped in frame headers:

Frame Format (per QR code): ┌─────────────────────────────┐ │ Header (8 bytes) │ ├─────────────────────────────┤ │ 1 byte: Frame format version│ │ 1 byte: Total frames (N) │ │ 1 byte: Current frame (i) │ │ 1 byte: Payload length │ │ 4 bytes: CRC32 checksum │ ├─────────────────────────────┤ │ Payload (up to 2953 bytes) │ ├─────────────────────────────┤ │ Total: ~2961 bytes per QR │ └─────────────────────────────┘ Example: Encrypted payload = 9000 bytes Max per QR = 2953 bytes Frames needed = ceil(9000 / 2953) = 4 QR codes

Multi-part sequence:

Phase 3: QR Code Generation

Each frame is encoded as a QR code (Version 40, Error Correction Level H):

Device A Display ┌──────────────────────────┐ │ ┌────────────────────┐ │ │ │ [QR CODE 1/4] │ │ Device displays first QR │ │ Encrypted Frame │ │ User scans with Device B │ │ ~150 bytes data │ │ │ └────────────────────┘ │ │ │ │ Part 1 of 4 │ │ Passphrase: [hidden] │ └──────────────────────────┘ (User clicks "next QR") ↓ Displays Frame 2/4...

QR Code Properties:

Phase 4: Scanning & Reassembly

Device B scans QR codes and reassembles the encrypted payload:

Device B Camera ┌──────────────────────────┐ │ Scanning QR 1/4... │ │ ████████████████████ │ Progress bar │ Payload: 2953/2953 bytes │ │ CRC32: ✓ Valid │ └──────────────────────────┘ ↓ (waiting for frame 2) Scanning QR 2/4... │ ████████████████████ │ │ Payload: 5906/5906 bytes │ │ CRC32: ✓ Valid │ └──────────────────────────┘ ↓ (waiting for frame 3) ... (frames 3, 4) ↓ Reassemble all frames ├─ Verify frame order (1/4, 2/4, 3/4, 4/4) ├─ Concatenate payloads ├─ Validate total CRC32 └─ Recover encrypted data

Reassembly process:

Phase 5: Decryption & Validation

Device B decrypts the reassembled payload and validates the key share:

Encrypted Data (from QR) ↓ User enters passphrase ↓ PBKDF2(passphrase, 100k iterations) → 256-bit key ↓ AES-256-GCM Decrypt ├─ Verify authentication tag ├─ Decompress (zlib) └─ Extract key material ↓ Validate Checksum ├─ BLAKE3(key data) ← compare └─ ✓ Match ↓ Parse Key ├─ Curve ID: secp256k1 ├─ Share 1: 32 bytes ├─ UUID: [device-b-unique-id] └─ Timestamp: [2026-03-11 01:40 UTC] ↓ ✓ Success: Key imported to Device B Keychain

Security checks:

Use Case: 2-Party with Device Backup

Scenario: Device A holds Share 0. User wants to back up Share 0 to Device B.

Timeline: Day 1 (Device A) ├─ Generate 2-party key ├─ Share 0 stored in Keychain └─ Share 1 sent to server Day 2 (Both devices) ├─ Device A: "Backup → Export to QR" │ ├─ Encrypt Share 0 with user passphrase │ ├─ Generate 4-part QR sequence │ └─ Display on screen │ ├─ Device B: "Import Key → Scan QR" │ ├─ Scan frames 1-4 │ ├─ Decrypt with passphrase │ └─ Import Share 0 to Keychain │ └─ Result: Both devices now have Share 0 Device A can sign with Device B (2-of-2 custody established) Recovery scenario: Device A lost/damaged ├─ Get Device C ├─ Restore backup from Device B │ └─ "Export to QR" → scan on Device C └─ Device C now has Share 0 Can pair with server (Share 1) to sign
Why Multi-Part QR? A single QR code is limited to ~4296 bytes of binary data. Encrypted + compressed key shares often exceed this (especially with metadata). Multi-part design allows distribution of larger payloads while keeping individual QR codes scannable on mobile phones.
Air-Gap Safety: QR transfer is completely offline. Device A generates QR codes, Device B scans them. No network connection needed. Share data never leaves the QR code unencrypted. Passphrase provides additional protection against shoulder surfers or photo theft.