From 8dd0a0df5def84588174e4c10a88b47ea4c85b70 Mon Sep 17 00:00:00 2001 From: juyung Date: Sun, 11 Oct 2026 16:14:19 +0000 Subject: [PATCH] Initial release --- README.md | 116 +++++++++++++++++++++++------------------------------- 1 file changed, 49 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 09fcbb5..025aa74 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,47 @@ # Post-Quantum Hybrid ML-KEM-1024 + AES-256-GCM File Encryption -Streaming hybrid file encryption: ML-KEM-1024 handles post-quantum key exchange, and AES-256-GCM handles bulk file encryption with built-in authenticity. The file signature is `KYB`, and the file extension is ".kyb". +kyb encrypts files using post-quantum cryptography (ML-KEM-1024) and AES-256-GCM authenticated encryption. The file signature is `KYB`, and the file extension is `.kyb`. -Simplified flow (ML-KEM-1024 + AES-256 only, HKDF omitted for clarity): +``` +ENCRYPTION DECRYPTION +═════════════════════════════════════════════════════════════════ - +Input File Input File (.kyb) + │ │ + ▼ ▼ +Generate IV (12B) Read Header + ML-KEM CT + IV + │ │ + ▼ ▼ +ML-KEM Encapsulation ML-KEM Decapsulation +(Public Key .pub) (Private Key .sec) + │ │ + └─→ Shared Secret (32B) └─→ Shared Secret (32B) + │ │ + ├─→ HKDF-SHA256 ├─→ HKDF-SHA256 + │ └─ Salt: IV │ └─ Salt: IV + │ │ + ▼ ▼ +AES-256 Key (32B) AES-256 Key (32B) + │ │ + ▼ ▼ +Encrypt File Decrypt File + │ │ + ▼ ▼ +Write Auth Tag Verify Auth Tag + │ │ + ▼ ▼ +Output File (.kyb) Output File + +``` ## Features -- Post-quantum secure key exchange via liboqs ML-KEM-1024 KEM (~256-bit PQ security) -- AES-256-GCM authenticated encryption with a streaming architecture that handles files larger than RAM (64 MB chunks) -- AES key derived from the ML-KEM shared secret via HKDF-SHA256 (never stored in the file) -- Unforgeable 128-bit GCM tag over the header + ciphertext to detect tampering or corruption -- Self-describing CBOR header (RFC 8949; file signature `KYB`, version, algorithm and length fields), so each file identifies its own format and unsupported future versions are rejected cleanly +- Compromising one file doesn't expose others. A fresh 32-byte shared secret is generated for each file and transformed into the AES-256 key via HKDF-SHA256. +- An attacker cannot modify files undetectably. Any tampering with the ciphertext, header, or nonce causes authentication to fail before plaintext is written to disk. +- Every encrypted file includes a header with detailed metadata, so you can rebuild a decryptor from scratch should the original source code ever be lost ## Requirements -- `oqs` ([liboqs-python](https://github.com/open-quantum-safe/liboqs-python)) -- `cryptography` ([pyca/cryptography](https://github.com/pyca/cryptography)) -- `cbor2` ([cbor2](https://github.com/agronholm/cbor2)) - ```bash python3 -m venv venv && . venv/bin/activate pip install -r requirements.txt @@ -35,77 +57,37 @@ python3 gen_keys.py Produces: -- `mlkem1024.pub` - public key (1568 bytes) -- `mlkem1024.sec` - secret key (3168 bytes) +- `mlkem1024.pub` - ML-KEM-1024 public key (1568 bytes). Used to encrypt files. You use it to encrypt files for yourself locally. You can share it with anyone to encrypt files for you. +- `mlkem1024.sec` - ML-KEM-1024 secret key (3168 bytes). Required to decrypt any file encrypted with your public key. Keep it secure and never share it. If lost, you permanently lose access to all encrypted files. If compromised, all encrypted files are exposed. 2. Encrypt a file ```bash -python3 encrypt.py archive.7z +python3 encrypt.py archive.tar ``` -Output: `archive.7z.kyb` +Output: `archive.tar.kyb` -The `.kyb` file is self-contained: a compact CBOR header at the start describes the exact format, algorithms, and lengths. See [File formats](#file-formats) for the layout. +The `.kyb` file is self-contained: a compact CBOR header at the start describes the exact format, algorithms, and lengths. See [File Structure](#file-structure) for the layout. 3. Decrypt a file ```bash -python3 decrypt.py archive.7z.kyb +python3 decrypt.py archive.tar.kyb ``` -Output: `archive.7z` +Output: `archive.tar` -The script automatically verifies the GCM tag. If the file has been tampered with, you'll see: +If the file has been tampered with, you'll see: `Error: Integrity check failed. File corrupted or tampered` and the temp file is discarded. -``` -Error: Integrity check failed. File corrupted or tampered -``` +## File Structure -and the temp file is discarded. No plaintext ever appears at the destination path until the tag has been verified. - -## File formats - -**Key files (raw binary)** - -File|Content|Size (bytes) --|-|- -`mlkem1024.pub`|ML-KEM-1024 public key|1568 -`mlkem1024.sec`|ML-KEM-1024 secret key|3168 - -**CBOR header** - -Layout: 3-byte signature `KYB` + 1-byte version, then a CBOR map (RFC 8949) of field name → value pairs. CBOR is self-delimiting, so the reader knows exactly where the map ends; unknown keys are simply ignored, keeping the format forward-compatible. The `KDF` and `INFO` fields record the key-derivation parameters, making the file fully self-describing: with the secret key alone, a from-scratch decryptor can derive the AES key from the header. - -Key | Value (v1) --|- -`KEM`|`MLKEM1024` -`CIPHER`|`AES256GCM` -`MLKEMCT`|`1568` -`IV`|`12` -`TAG`|`16` -`KDF`|`HKDF-SHA256` -`INFO`|`mlkem-aes-key` - -**Encrypted file structure** - -`archive.7z.kyb`: +`archive.tar.kyb`: Section | Size | Description -|-|- -CBOR header|91 bytes (v1)|Signature `KYB` (3 B) + version (1 B) + CBOR map (87 B) -ML-KEM ciphertext|1568 bytes|Encapsulated key (ciphertext from ML-KEM-1024); length read from the header -IV (nonce)|12 bytes|GCM nonce, also the HKDF salt; length read from the header -File ciphertext|same as plaintext|AES-256-GCM encrypted chunks, streamed in 64 MB blocks -GCM auth tag|16 bytes|Tag over the header + ML-KEM CT + IV + all ciphertext; length read from the header - -## Security notes - -- A fresh 32-byte **ML-KEM shared secret** is generated **per file** by `encap_secret()` and recovered only with `mlkem1024.sec` via `decap_secret()`. It is the root key material: neither the AES key nor the ML-KEM private key. -- The AES key is **derived from that ML-KEM shared secret** with HKDF-SHA256 (domain-separated `info` label, both recorded in the header), so no key material is ever stored in the file. -- Because the AES key is only derivable by the legitimate recipient (ML-KEM decapsulation), the GCM tag is **unforgeable**: an attacker without the secret key cannot modify the file undetectably. -- The GCM tag is computed over the **CBOR header + ML-KEM CT + IV + AES ciphertext** (via additional authenticated data), so any tampering with the encrypted data, the nonce, or the format header is detected before decryption. -- Decrypted plaintext is written to a temporary file and atomically renamed into place **only after** the GCM tag verifies. -- The header carries a format **version**; decrypt checks it up front, so a file written by a newer (or unknown) format is refused with a clear error instead of being mis-parsed. -- ML-KEM-1024 is believed to offer security equivalent to ~256-bit classical keys against quantum attackers. -- The secret key file (`mlkem1024.sec`) is the single point of failure. Losing it means losing every encrypted file. Treat it like a private SSH key: keep it offline, back it up, and restrict access (e.g. `chmod 600`). For stronger protection, consider encrypting the key file with a passphrase or splitting it into pieces (XOR-splitting or Shamir secret sharing) across separate locations. +CBOR header|91 bytes (v1)|Signature `KYB` (3 B) + version (1 B) + CBOR map (87 B): `{"KEM": "MLKEM1024", "CIPHER": "AES256GCM", "MLKEMCT": 1568, "IV": 12, "TAG": 16, "KDF": "HKDF-SHA256", "INFO": "mlkem-aes-key"}` | +ML-KEM ciphertext|1568 bytes|Encrypted shared secret. Your secret key (`mlkem1024.sec`) decrypts it to derive the AES-256 key that unlocks your file +IV (nonce)|12 bytes|12-byte nonce for AES-256-GCM, reused as salt for HKDF-SHA256 key derivation +File ciphertext|same as plaintext|AES-256-GCM encrypted chunks +GCM auth tag|16 bytes|16-byte authentication code that proves the file hasn't been tampered with. If any byte is modified, decryption fails