File Transfer
Every file stripped, chunked, hashed, encrypted, and transferred with zero metadata leakage.
File Pipeline Overview
SELECT FILE
|
v
METADATA STRIP (EXIF, GPS, timestamps, camera info)
|
v
BLAKE3 HASH (content-addressable integrity check)
|
v
CHUNK (512 KB blocks)
|
v
PER-CHUNK ENCRYPT (AES-256-GCM, unique key per file)
|
v
TRANSFER (chunks sent over P2P via Tor)
|
v
REASSEMBLE (recipient verifies BLAKE3 hash)
|
v
DECRYPT → MEDIA CACHE (encrypted at rest)
Step 1: Metadata Stripping
Before any encryption or transmission, RVNT strips all metadata from the file. Metadata in images, videos, and documents can reveal information the sender did not intend to share.
What Is Stripped
| Metadata Type | Example Content | Risk |
|---|---|---|
| EXIF GPS | 37.7749, -122.4194 | Reveals exact location where photo was taken |
| EXIF DateTime | 2024:03:15 14:32:07 | Reveals when photo was taken |
| Camera Model | iPhone 15 Pro Max | Reveals device type, narrows identity |
| Serial Number | Camera or lens serial | Unique device identifier |
| Thumbnail | Embedded preview image | May contain unedited original (even if photo was cropped) |
| Software | Adobe Photoshop CC 2024 | Reveals editing software, potential fingerprint |
| PDF Author | John Smith | Reveals creator identity |
| DOCX Revision | Edit history, tracked changes | Reveals editing history, contributor names |
Stripping implementation by file type:
Images (JPEG, PNG, HEIC, WebP):
- Remove all EXIF data (exif crate)
- Remove XMP metadata
- Remove IPTC metadata
- Remove embedded thumbnails
- Preserve image data and ICC color profile only
Videos (MP4, MOV, WebM):
- Remove metadata atoms (moov/udta, moov/meta)
- Remove GPS tracks
- Remove creation/modification timestamps
- Remove device information
- Preserve video/audio streams only
Documents (PDF):
- Remove /Author, /Creator, /Producer metadata
- Remove XMP metadata stream
- Remove embedded JavaScript
- Preserve document content
All other files:
- Sent as-is (no metadata stripping possible)
- User warned: "This file type may contain metadata" Metadata stripping is best-effort. New metadata formats and embedding techniques are continuously developed. RVNT strips all known metadata types, but novel or proprietary metadata may not be detected. For maximum safety, manually strip metadata before sending sensitive files.
Step 2: BLAKE3 Hashing
After metadata stripping, RVNT computes a BLAKE3 hash of the stripped file. This hash serves multiple purposes:
file_hash = BLAKE3(stripped_file_bytes) // 32 bytes
Purposes:
1. Integrity verification: recipient verifies hash after reassembly
2. Deduplication: if the same file is sent twice, it is not re-transferred
3. Content addressing: chunks are identified by file_hash + chunk_index
4. Resume support: partially transferred files can resume from last chunk
BLAKE3 properties:
- 256-bit output (32 bytes)
- Faster than SHA-256 (~3x on modern CPUs)
- Tree-hashing mode enables parallel computation
- Cryptographically secure (collision + preimage resistant) Step 3: Chunking
Files are split into fixed-size chunks for transfer. Chunking enables resume, parallel transfer, and limits memory usage.
Chunk parameters:
Chunk size: 512 KB (524,288 bytes)
Last chunk: Variable (remainder of file)
Max file size: 2 GB (4096 chunks maximum)
Chunk numbering: 0-indexed, sequential
Example:
File size: 2.5 MB (2,621,440 bytes)
Chunks: 5
Chunk 0: bytes [0 .. 524,287] (512 KB)
Chunk 1: bytes [524,288 .. 1,048,575] (512 KB)
Chunk 2: bytes [1,048,576 .. 1,572,863] (512 KB)
Chunk 3: bytes [1,572,864 .. 2,097,151] (512 KB)
Chunk 4: bytes [2,097,152 .. 2,621,439] (remainder, 512 KB) Step 4: Per-Chunk Encryption
Each file is encrypted with a unique per-file key. Individual chunks are encrypted with keys derived from the file key and chunk index.
Key derivation:
file_key = random_256bit() // 32 bytes, generated once per file
Per-chunk encryption:
for each chunk_index in 0..num_chunks:
chunk_key = HKDF-SHA256(
ikm: file_key,
salt: file_hash,
info: "rvnt-file-chunk-" || BE32(chunk_index),
len: 32
)
nonce = BE32(chunk_index) || random_64bit() // 96 bits
encrypted_chunk = AES-256-GCM(
key: chunk_key,
nonce: nonce,
aad: file_hash || BE32(chunk_index) || BE32(num_chunks),
data: chunk_bytes
)
secure_zero(chunk_key)
The file_key is sent to the recipient inside the message body
(which is itself Double Ratchet encrypted):
Attachment {
hash: file_hash, // BLAKE3 of stripped file
filename: "photo.jpg", // Original filename (optional)
mime_type: "image/jpeg",
size: 2621440, // Stripped file size
key: file_key, // Per-file encryption key
} Step 5: Network Transfer
Transfer protocol:
1. Sender sends message with Attachment metadata
2. Recipient acknowledges and requests chunks
3. Chunks transferred via libp2p stream:
ChunkRequest {
file_hash: [32 bytes]
chunk_index: u32
}
ChunkResponse {
file_hash: [32 bytes]
chunk_index: u32
total_chunks: u32
encrypted_data: [variable, up to 512 KB + 16 byte GCM tag]
nonce: [12 bytes]
}
Transfer behavior:
- Sequential by default (simple, reliable)
- Parallel: up to 4 concurrent chunk transfers (optional)
- Resume: if transfer is interrupted, resume from last
successfully received chunk
- Verification: each chunk verified by GCM tag on decrypt
- Full file verification: BLAKE3(reassembled) == file_hash
All chunk transfers route through Tor (same as messages) Step 6: Reassembly and Verification
Recipient reassembly:
1. Receive all chunks
2. Decrypt each chunk with derived chunk_key
3. Concatenate decrypted chunks in order
4. Compute BLAKE3 hash of reassembled file
5. Compare with file_hash from message metadata
6. If match: file is intact and authentic
7. If mismatch: file is corrupted or tampered, discard + alert user Step 7: Media Cache
Decrypted files are stored in RVNT's encrypted media cache for display in the UI.
Media cache:
Location: {app_data}/media_cache/
Encryption: Each file re-encrypted with a cache-specific key
derived from the database encryption key
Thumbnails: Generated locally, stored encrypted
Max size: Configurable (default: 1 GB)
Eviction: LRU (least recently used) when cache exceeds max
Wipe: Included in panic mode destruction sequence
Cache key derivation:
cache_key = HKDF-SHA256(
ikm: database_key,
info: "rvnt-media-cache",
len: 32
)
Files in cache are NOT the original files. They are:
1. Metadata-stripped
2. Re-encrypted with cache_key
3. Stored with a random filename (no relationship to original name) Supported File Types
| Category | Types | Max Size | Metadata Strip |
|---|---|---|---|
| Images | JPEG, PNG, HEIC, WebP, GIF | 50 MB | Full EXIF/XMP/IPTC |
| Videos | MP4, MOV, WebM | 500 MB | Metadata atoms, GPS |
| Audio | MP3, AAC, OGG, FLAC | 100 MB | ID3 tags, comments |
| Documents | PDF, TXT, CSV | 100 MB | PDF metadata |
| Other | Any file type | 2 GB | None (warned) |
Further Reading
- Messaging -- Text message lifecycle and status system
- How It Works -- Full encryption pipeline
- Panic Mode -- How media cache is destroyed in an emergency