Hybrid Encryption Guide¶
qcrypto uses hybrid encryption: a post-quantum KEM (Kyber) establishes a shared secret, which is then used with classical AES-256-GCM for authenticated encryption.
How It Works¶
┌─────────────────────────────────────────────────────────────┐
│ Encryption │
├─────────────────────────────────────────────────────────────┤
│ 1. Kyber encapsulates → ciphertext + shared_secret │
│ 2. HKDF-SHA256 derives AES key from shared_secret │
│ 3. AES-256-GCM encrypts plaintext │
│ 4. Output: header + kyber_ct + nonce + aes_ciphertext │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Decryption │
├─────────────────────────────────────────────────────────────┤
│ 1. Parse header, extract Kyber ciphertext │
│ 2. Kyber decapsulates → shared_secret │
│ 3. HKDF-SHA256 derives same AES key │
│ 4. AES-256-GCM decrypts and verifies │
└─────────────────────────────────────────────────────────────┘
Basic Usage¶
Encrypt/Decrypt Bytes¶
from qcrypto import KyberKEM, encrypt, decrypt
# Setup
kem = KyberKEM("Kyber768")
keys = kem.generate_keypair()
# Encrypt
plaintext = b"Sensitive data"
ciphertext = encrypt(keys.public_key, plaintext)
# Decrypt
recovered = decrypt(keys.private_key, ciphertext)
assert recovered == plaintext
Encrypt/Decrypt Files¶
For large files, use streaming encryption which doesn't load the entire file into memory:
from qcrypto import encrypt_file, decrypt_file, KyberKEM
# Load keys
pub = KyberKEM.load_public_key("recipient.pub")
priv = KyberKEM.load_private_key("my.key")
# Encrypt a file (streaming)
encrypt_file(pub, "large_video.mp4", "large_video.mp4.enc")
# Decrypt a file (streaming)
decrypt_file(priv, "large_video.mp4.enc", "large_video.mp4")
Armored Messages¶
For email or chat, use ASCII-armored encoding:
from qcrypto import encrypt_message_armored, decrypt_message_armored
# Encrypt to armored format
armored = encrypt_message_armored(pub, b"Secret message")
print(armored)
# -----BEGIN QCRYPTO MESSAGE-----
# AgEEQJg/+TQjIxlLvaPaBU5VKaXS...
# -----END QCRYPTO MESSAGE-----
# Decrypt armored message
plaintext = decrypt_message_armored(priv, armored)
Ciphertext Format¶
qcrypto uses a self-describing binary format:
┌──────────────────────────────────────────────────────────┐
│ Byte 0 │ Version (currently 2) │
├─────────────┼────────────────────────────────────────────┤
│ Byte 1 │ Algorithm ID (1 = Kyber768) │
├─────────────┼────────────────────────────────────────────┤
│ Bytes 2-3 │ Kyber ciphertext length (big-endian) │
├─────────────┼────────────────────────────────────────────┤
│ Bytes 4-7 │ CRC32 checksum of header (v2) │
├─────────────┼────────────────────────────────────────────┤
│ N bytes │ Kyber ciphertext │
├─────────────┼────────────────────────────────────────────┤
│ 12 bytes │ AES-GCM nonce │
├─────────────┼────────────────────────────────────────────┤
│ M bytes │ AES-GCM ciphertext + 16-byte tag │
└─────────────┴────────────────────────────────────────────┘
The header checksum (v2) provides helpful error messages for corrupted files.
Key Management¶
Generate Keys¶
kem = KyberKEM("Kyber768")
keys = kem.generate_keypair()
# Save keys
kem.save_public_key("my.pub", encoding="armor")
kem.save_private_key("my.key", encoding="armor", passphrase="secret")
Load Keys¶
# Load public key (auto-detects armor)
pub = KyberKEM.load_public_key("my.pub")
# Load private key with passphrase
priv = KyberKEM.load_private_key("my.key", passphrase="secret")
Key Fingerprints¶
Fingerprints help verify key identity:
from qcrypto import key_fingerprint
fp = key_fingerprint(pub)
print(f"Key: {fp}") # "a1b2c3d4e5f67890..."
Security Considerations¶
What qcrypto provides
- Post-quantum security via Kyber768 (NIST Level 3)
- Authenticated encryption via AES-256-GCM
- Forward secrecy per-message (fresh encapsulation)
- Integrity protection for header and payload
What qcrypto does NOT provide
- Key exchange protocols
- Identity verification (no PKI)
- Replay protection (application responsibility)
- Metadata hiding (file sizes visible)
Algorithm Details¶
| Component | Algorithm | Security Level |
|---|---|---|
| KEM | Kyber768 | NIST Level 3 (~AES-192) |
| KDF | HKDF-SHA256 | 256-bit |
| AEAD | AES-256-GCM | 256-bit |
| Nonce | Random 96-bit | Per-message |