- Python 100%
Move classifiers and dependencies back under [project] section, place [project.urls] after dependencies. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| docs | ||
| src/qrbackup | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
QRBackup
Reliable paper backup using QR codes with optional encryption, erasure coding, and Shamir's Secret Sharing.
Why Paper Backups?
Digital storage fails. Hard drives crash, SSDs degrade, cloud services shut down, and file formats become obsolete. For truly critical data - encryption keys, cryptocurrency seeds, password vaults, or irreplaceable documents - you need a backup medium that:
- Lasts decades without power or maintenance
- Survives disasters (fire-resistant safes, bank vaults)
- Remains readable with commodity technology
- Can be visually verified for tampering
Paper, properly stored, meets all these criteria. QRBackup encodes your data into high-density QR codes that can be printed, stored, and later scanned to recover the original file.
Key Features
- High-Density Encoding: Up to ~2.9 KB per QR code using Version 40 codes
- Automatic Compression: zstd compression reduces page count for compressible data
- Strong Encryption: AES-256-GCM with Argon2id key derivation (64MB memory-hard)
- Erasure Coding: Reed-Solomon coding recovers data even when QR codes are damaged or unreadable
- Secret Sharing: Shamir's Secret Sharing splits backups across multiple locations (K-of-N threshold)
- Print-Ready PDFs: Clean layouts with metadata headers, optimized for reliable scanning
Example Output
Installation
uv pip install -e .
System Dependencies
zbarlibrary for QR code readingliberasurecodefor erasure coding support
On macOS:
brew install zbar
# liberasurecode must be compiled from source
git clone https://github.com/openstack/liberasurecode.git
cd liberasurecode
./autogen.sh && ./configure --prefix=$HOME/.local && make && make install
# Add to your shell profile (.zshrc or .bashrc)
export DYLD_LIBRARY_PATH=$HOME/.local/lib
On Debian/Ubuntu:
apt-get install libzbar0 liberasurecode-dev
Usage
Basic encoding
qrbackup encode secret.txt -o backup.pdf
With encryption (recommended for sensitive data)
qrbackup encode secret.txt -o backup.pdf --password
With erasure coding (recommended for archival)
# 20% redundancy = can lose ~20% of QR codes and still recover
qrbackup encode data.bin -o backup.pdf --redundancy 20
With secret sharing (for distributed trust)
# Creates 3 PDFs, any 2 can reconstruct the original
qrbackup encode keys.gpg -o backup.pdf --split 2-of-3
Decoding
qrbackup decode backup.pdf -o recovered.txt
# Encrypted backup
qrbackup decode backup.pdf -o recovered.txt --password
Verification (without decoding)
qrbackup verify backup.pdf
How It Works
Encoding Pipeline
File → [Compress] → [Encrypt] → Chunk → Erasure Code → QR Codes → PDF
- Compression: zstd compresses the input (skip with
--no-compress) - Encryption: AES-256-GCM encrypts the compressed data (optional)
- Chunking: Data is split into chunks sized for QR capacity
- Erasure Coding: Reed-Solomon adds parity chunks for recovery (optional)
- QR Generation: Each chunk becomes a QR code with a binary header
- PDF Layout: QR codes are arranged on pages with metadata headers
Chunk Format
Each QR code contains a 47-byte header followed by data:
| Field | Size | Description |
|---|---|---|
| Magic | 4B | QRB2 version identifier |
| Flags | 1B | Compressed, encrypted, parity chunk, etc. |
| Data chunks | 2B | Number of data chunks (N) |
| Parity chunks | 2B | Number of parity chunks (M) |
| Chunk index | 2B | This chunk's index (0..N+M-1) |
| SHA-256 | 32B | Hash of original uncompressed data |
| Original length | 4B | For padding removal |
QR Code Sizes
| Size | QR Version | Capacity | Best For |
|---|---|---|---|
| small | V18 (89 modules) | ~718 bytes | Large files, many codes per page |
| medium | V30 (137 modules) | ~1.7 KB | Most files, balanced density |
| large | V40 (177 modules) | ~2.9 KB | Small files, fewer large codes |
| xlarge | V18 (8px/module) | ~718 bytes | Maximum reliability, easy scanning |
Erasure Coding
QRBackup uses Reed-Solomon erasure coding via liberasurecode. With --redundancy 20:
- Your data is split into N data chunks
- M parity chunks are generated (M ≈ 20% of N)
- Any N chunks (data or parity) can reconstruct the original
- You can lose up to M chunks and still recover
For large files exceeding the 32-fragment limit, data is automatically striped across multiple erasure groups.
Encryption
When using --password or --keyfile:
- Key Derivation: Argon2id with 64MB memory, 3 iterations, 4 threads
- Cipher: AES-256-GCM (authenticated encryption)
- Overhead: 44 bytes (16B salt + 12B nonce + 16B auth tag)
Encryption happens before chunking, so the entire backup is protected. Erasure coding is automatically enabled (20% redundancy) for encrypted backups to prevent single-chunk failures from destroying the ciphertext.
CLI Reference
Encode options
| Option | Description |
|---|---|
-o, --output |
Output PDF file path (required) |
--no-compress |
Disable zstd compression |
--qr-size |
QR size: small, medium, large, xlarge, auto (default: auto) |
--dpi |
Target print/scan DPI (default: 300) |
--pixels-per-module |
Pixels per QR module (default: 4) |
-r, --redundancy |
Erasure coding percentage (e.g., 20 for 20% parity) |
--split K-of-N |
Shamir's Secret Sharing (e.g., 2-of-3) |
--page-size |
Page size: A4, letter (default: A4) |
-p, --password |
Encrypt with password |
-k, --keyfile |
Encrypt with 256-bit key file |
--hint |
Password hint printed in PDF header |
-v, --verbose |
Verbose output |
Decode options
| Option | Description |
|---|---|
-o, --output |
Output file path (required) |
--combine K |
Number of SSSS shares being combined |
-p, --password |
Decrypt with password |
-k, --keyfile |
Decrypt with key file |
-v, --verbose |
Verbose output |
Verify options
| Option | Description |
|---|---|
-v, --verbose |
Verbose output |
Best Practices
- Always use redundancy for archival backups:
--redundancy 20or higher - Test your backup by decoding it before storing
- Use encryption for sensitive data:
--passwordor--keyfile - Print on acid-free paper for longevity
- Store multiple copies in different locations
- Consider secret sharing for critical keys:
--split 2-of-3
Requirements
- Python 3.12+
zbarlibrary for QR code readingliberasurecodelibrary for erasure coding
License
QRBackup is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
See LICENSE for the full text.
