Full interactive documentation: qeltrix-v6.netlify.app
What Is Qeltrix V6?
Most encryption tools work the same way they did decades ago. You hand over a file, it gets locked, and to read a single byte of it you must decrypt the whole thing first. Seeking through an encrypted video file meant downloading the entire thing. Extracting a single log entry from a 500 GB encrypted backup meant unpacking the whole archive.
Qeltrix V6 is a new encrypted container format that throws out that assumption. It is built around one core idea: an encrypted file should behave like a seekable stream, not a locked safe. You should be able to jump to any position, request any byte range, and receive exactly those bytes — decrypted — without the system touching anything else.
The full technical documentation, CLI reference, Python API guide, deployment patterns, and security analysis live at qeltrix-v6.netlify.app. This article explains the ideas behind it and why they matter.
The Core Idea: Independent Blocks
The reason traditional encryption can't be seeked is that it treats the entire file as one object. Decrypt the end of the file and you've necessarily processed everything before it.
V6 takes a different approach. Every file is split into fixed-size blocks — 1 MB by default — and each block is encrypted independently with its own unique key, its own IV, its own authentication tag. The blocks are then packed into a .qltx container with a footer index that maps original byte offsets to block positions.
Traditional: [ one big encrypted blob — all or nothing ]
Qeltrix V6: [ Header ] [ Block 0 ] [ Block 1 ] ... [ Block N ] [ Footer/Index ]
each block independently encrypted + authenticated
This changes what seeking costs. Instead of "decrypt everything up to the point you want," the cost becomes "look up the block containing your byte offset in the footer index, decrypt that block, slice out the bytes you need." For a 20 GB video, seeking to the 18-minute mark might decrypt two or three blocks — a few megabytes — instead of gigabytes.
The Key Hierarchy
The encryption design uses two layers of keys. Understanding both is important for understanding what V6 actually protects.
The Master Key (MK) is a 32-byte symmetric secret that acts as the root of trust for the entire container. It is never written to disk in plaintext. The container header stores an encrypted copy of it (wrapped with a passphrase-derived key), but that wrapped blob is useless without the passphrase. Every operation that touches the container — packing, unpacking, seeking, serving — requires the caller to supply the MK at runtime.
Content Derived Keys (CDKs) are per-block keys derived from the MK using HKDF-SHA256. Each CDK is derived from a combination of the master key, the block's sequential index, a SHA-256 hash of the block's raw content, and a random salt. This dual binding — to both position and content — has a meaningful security consequence: two identical blocks at different positions will have different keys, and if a block is moved to a different position without re-encryption, authentication will fail. The system detects it.
Passphrase
↓ PBKDF2-SHA256
Master Key (MK)
↓ HKDF-SHA256 + block_index + data_hash + salt
CDK for Block N CDK for Block M
↓ AES-256-GCM or ChaCha20-Poly1305
Encrypted Block N Encrypted Block M
Critically, compromising one block's CDK reveals nothing about any other block's key. The CDKs are mathematically independent.
What the V6-C Metadata Actually Is
Each block in a .qltx container carries a structure called V6-C metadata alongside the ciphertext. This metadata holds everything needed to independently decrypt and verify that one block:
- The per-block IV (nonce for the AEAD cipher)
- The HKDF salt used to derive this block's CDK
- The SHA-256 hash of the block's original (unencrypted) content
- The CDK itself, wrapped (re-encrypted) with the master key
- The cipher identifier (AES-GCM or ChaCha20)
- The original and compressed block sizes
The V6-C metadata is itself encrypted with the master key. This means that without the MK, you can't even learn anything about the block's internal structure — the IV, the salt, and the content hash are all opaque to an observer who doesn't hold the key.
This is what makes the container format genuinely seekable without compromising security: each block is a self-contained, independently verifiable unit, and the footer index is the table of contents that maps byte offsets to those units.
Cipher Choices: AES-256-GCM and ChaCha20-Poly1305
V6 supports two AEAD ciphers, and the choice matters depending on your hardware.
AES-256-GCM is the default. On any CPU with AES hardware acceleration (AES-NI instructions, present in virtually all processors manufactured after 2010), it runs at several gigabytes per second. If you're deploying on modern server or desktop hardware, this is almost certainly the right choice.
ChaCha20-Poly1305 is the mobile-friendly alternative. It was designed to be fast in pure software, without hardware acceleration. On IoT devices, older ARM processors, or embedded systems where AES-NI isn't available, ChaCha20 can be meaningfully faster. It provides the same security guarantees — 256-bit keys, 16-byte AEAD authentication tags, identical tamper-detection properties.
Both ciphers authenticate every block with a 16-byte tag. Any modification to any byte of any block — even flipping a single bit — causes the authentication check to fail and decryption to abort with an error. This tamper-evidence is not a separate step or an add-on; it is baked into the encryption itself.
HTTP Range Requests: Seeking Over the Network
The most practically significant feature of V6 is its native HTTP Range Request support. Range Requests are the mechanism that allows you to seek in a YouTube video without buffering from the beginning — your browser sends a request for bytes=50000000-60000000 and the server returns just those bytes with a 206 Partial Content response.
V6's SeekServer brings this capability to encrypted files. The server receives a Range Request, consults the footer's VFS (Virtual File System) index to identify which blocks cover the requested byte range, fetches and decrypts only those blocks, and returns exactly the requested bytes. The client — a media player, a browser, a download manager — never needs to know about the block structure. It just gets its bytes.
Seek cost for a 20 GB encrypted video:
Byte range: bytes=16,384,000,000–16,385,048,575
Blocks needed: 2 (2 MB of 20 GB read from disk)
Data touched: 0.01% of the container
Response time: milliseconds
The documentation at qeltrix-v6.netlify.app covers the full SeekServer setup, including how to put it behind nginx or Caddy for HTTPS, and how to test it with curl's -H "Range: bytes=X-Y" flag.
The Gateway: Encrypting Live Streams
Beyond static files, V6 includes a GatewayServer — a TCP encryption router that can wrap any stream of data into V6's block-encrypted format in real time. Raw bytes come in one side; authenticated, block-framed V6 ciphertext goes out the other.
The Gateway runs in one of three topologies:
Reflect mode is for testing. The gateway encrypts incoming data and sends the V6 stream back to the same sender. Useful for benchmarking and verifying that the encryption pipeline is working.
Router mode is the production pattern. A data source sends a raw TCP stream to the gateway; the gateway encrypts it and forwards the V6 stream to a destination. The destination — a storage backend, another service, a relay — receives only ciphertext. Even if the destination is compromised, it has no key.
Chained mode connects multiple gateways in series. Each gateway wraps the stream with its own master key. Data passing through three gateways is triple-encrypted under three independent keys; compromising any one node doesn't expose the plaintext.
The GatewayServer uses a thread pool to handle simultaneous connections, with each connection maintaining its own independent block counter and CDK chain. Encryption throughput scales approximately linearly with available CPU cores up to the pool limit.
How Parallel Processing Works
Both the packer and the gateway are designed for throughput. Packing a file doesn't encrypt blocks one at a time in sequence — it dispatches block encryption jobs to a ThreadPoolExecutor, letting multiple blocks be encrypted simultaneously across all available CPU cores. On modern hardware with AES-NI, a well-parallelised V6 pack operation can saturate memory bandwidth rather than CPU compute.
The same design applies to unpacking and to the gateway. Each worker thread maintains its own state — its own cipher instance, its own block counter, its own CDK derivation — so threads never need to coordinate or synchronise on cryptographic operations. The shared state is limited to the master key, which is read-only after startup.
What Makes V6 Useful
The combination of seekable blocks, AEAD authentication, and the HTTP Range Request interface makes V6 a practical building block for a specific set of problems that conventional encryption doesn't handle well.
Encrypted video streaming. Store video libraries in encrypted .qltx containers on S3, GCS, or any cloud object store. Serve them with the SeekServer. Users can seek and play. The storage provider sees only ciphertext. CDN nodes can cache and deliver the encrypted blocks without ever holding a key.
Partial restore from encrypted backups. Back up large datasets into .qltx containers. When you need to restore a single file from a 500 GB backup, seek directly to that file's blocks and decrypt only them. No full extraction needed.
Real-time encrypted logging. Route log streams through the GatewayServer before writing to disk or forwarding to a log aggregator. Logs are stored in V6 format. Analysis tools that hold the key can seek to any time window. Anyone without the key sees ciphertext.
Zero-trust microservice data buses. In a microservices environment, service pairs can route their data traffic through V6 gateway pairs. The internal network fabric sees only V6 ciphertext. A compromised internal service cannot read traffic addressed to other services.
Tamper-evident archival. Every block carries a SHA-256 content hash and an AEAD authentication tag. Any modification to any byte of a container — even a single bit flip — causes the affected block's decryption to fail. This makes V6 containers a natural fit for compliance environments (HIPAA, PCI-DSS, SOC 2) where tamper-evidence is a requirement.
Capacity Overview
Block-level overhead (per block):
Block prefix: 28 bytes
V6-C metadata: ~128 bytes (encrypted)
AEAD tag: 16 bytes
──────────────────────────────
Overhead/block: ~172 bytes
For 1 MB blocks:
Overhead ratio: ~0.017% (172 bytes / 1,048,576 bytes)
Seek cost (20 GB file, 1 MB blocks):
Worst case: 2 blocks decrypted (~2 MB read)
Best case: 1 block decrypted (~1 MB read)
Index lookup: O(1) via footer VFS index
Container index (footer):
Per-block entry: ~96 bytes
1000-block file: ~96 KB index
The overhead is low by design. The goal is to make encryption not a performance penalty for seekable access — and for most workloads, the block overhead is negligible compared to the data being stored.
The PoC Status: What to Know Before Deploying
V6 is explicitly a proof of concept. The block encryption, CDK derivation, AEAD authentication, gateway architecture, and Range Request support are all production-quality in design. But there are three things that must change before real deployment:
The PBKDF2 salt is hardcoded. In the current codebase (cli.py), the passphrase-to-MK derivation uses a fixed salt (b"QeltrixV6Salt"). This means two users with the same passphrase derive the same master key, and an attacker could precompute a table of common passphrases. The fix is simple — generate a random 32-byte salt per container and store it in the header — but it hasn't been implemented yet.
There is no MK distribution mechanism. V6 does not solve the problem of how two nodes (a GatewayServer and a SeekServer, for example) securely share the same master key. That's deliberate — it's a routing component, not a key authority — but it means you need to design this layer yourself. The documentation covers three approaches: ECDH ephemeral key exchange, RSA key encapsulation, and integration with an external KMS (AWS KMS, HashiCorp Vault, etc.).
There is no key rotation. A compromised master key exposes all data encrypted under it, past and future, with no re-key mechanism in place. This is the most significant operational gap between the PoC and a production system.
The full PoC-to-production checklist is in the Security Notes section of the documentation at qeltrix-v6.netlify.app.
Getting Started
The quickest way to try V6 is via PyPI:
pip install qeltrix-v6
Pack a file, inspect the container, and unpack it:
python -m qeltrix_v6 pack myfile.mp4 myfile.qltx --passphrase secret
python -m qeltrix_v6 info myfile.qltx
python -m qeltrix_v6 unpack myfile.qltx recovered.mp4 --passphrase secret
Serve it over HTTP with Range Request support:
python -m qeltrix_v6 serve myfile.qltx --port 7621 --passphrase secret
Then seek to any position with any HTTP client that supports range requests — curl, VLC, a browser, ffmpeg. The documentation has full examples for all of these.
The full CLI reference, Python API documentation, deployment guides, and security analysis are at qeltrix-v6.netlify.app.
Qeltrix V6 — by Muhammed Shafin P (@hejhdiss) · Licensed CC BY-SA 4.0
Top comments (0)