Filie Protocol
This is the public specification for Filie's application-layer transfer protocol and cryptographic design. Filie uses open, documented control messages and standard cryptographic primitives to protect file transfers without depending on the secrecy of the protocol itself.
The specification covers the wire-visible protocol, key agreement, key derivation, authenticated encryption, and security boundaries. Local storage policy, UI behavior, service deployment, transfer retention, and operational tuning are implementation profiles layered on top of the core protocol.
Goals
Filie follows a zero-trust computing model for transfer infrastructure: the network, relay services, and object storage are treated as untrusted. File contents are encrypted on the sending device and decrypted only on the receiving device. The shared encryption secret is derived locally by the participating devices and is never transmitted over the wire or stored by Filie infrastructure. Filie infrastructure does not know, and cannot derive, the contents of encrypted chunks.
The protocol is designed to provide:
- End-to-end confidentiality for file contents.
- Authentication of device announcements and transfer intents.
- Bounded exposure when short-term key material is retained for offline or delayed delivery.
- Independent encryption of file chunks.
- Operation over LAN paths and cloud-assisted relay/storage paths.
The protocol does not attempt to protect plaintext from a device that is already compromised before encryption or after decryption.
Terminology
- Device identity key: A long-term Ed25519 signing key generated on a device. It identifies and authenticates the device.
- Ephemeral agreement key: A short-term X25519 key used for key agreement.
- Shared secret: The output of X25519 key agreement between the sender and receiver ephemeral keys.
- Transfer key: A symmetric key derived from the shared secret for a specific transfer context.
- Chunk: A contiguous segment of a file encrypted independently under the transfer key.
- Relay: Any service used for coordination, presence, transfer state, metadata delivery, or encrypted chunk storage.
Cryptographic Primitives
The current protocol profile uses:
- Ed25519 for device identity signatures.
- X25519 for ephemeral Diffie-Hellman key agreement.
- HKDF-HMAC-SHA-256 for key derivation.
- AES-256-GCM for authenticated encryption.
- Random AEAD nonces generated by the encryption library.
- Base64url without padding for public keys, nonces, and signatures in JSON.
All private keys and symmetric keys are generated and used on client devices. Relay services receive public keys, signed envelopes, transfer state, and encrypted chunks, but not private keys, shared secrets, transfer keys, or plaintext.
Device Identity
Each device generates an Ed25519 identity keypair:
ID_priv, ID_pub = Ed25519.Generate()
ID_priv remains local to the device. ID_pub is included in signed device announcements and transfer messages. Identity keys are used for signatures only; they are not used directly as encryption keys or key-agreement keys.
Ephemeral Agreement Keys
Each device maintains a short-term X25519 keypair:
E_priv, E_pub = X25519.Generate()
The public key E_pub may be advertised through LAN discovery or cloud device registration. The private key E_priv remains local.
Ephemeral key rotation and retention are protocol profile parameters. A Filie implementation may retain a bounded history of recent ephemeral private keys so that delayed transfers encrypted for a recently advertised public key can still be received. The exact retention window is not part of the core wire protocol. Deployments should document their chosen retention profile separately.
Signed Device Envelope
Devices advertise identity and agreement material with signed envelopes. The signature binds the device identity to the advertised ephemeral key and a fresh nonce.
WAN/cloud device envelope:
{
"hdr": {
"nonce": "BASE64URL(16 random bytes)",
"sig": "BASE64URL(Ed25519 signature)"
},
"body": {
"device": {
"id": "device identifier",
"name": "device display name",
"platform": "platform identifier",
"identity": "BASE64URL(Ed25519 public key)"
},
"wan": {
"ephemeral": "BASE64URL(X25519 public key)"
},
"discovery": {
"ttl": 300
}
}
}
The WAN signature payload is the following fixed-field JSON string:
{"id":"...","name":"...","platform":"...","identity":"...","wan_ephemeral":"...","nonce":"..."}
LAN discovery uses the same structure with a lan object:
{
"msg": "device",
"ver": 1,
"hdr": {
"ask": true,
"nonce": "BASE64URL(16 random bytes)",
"sig": "BASE64URL(Ed25519 signature)"
},
"body": {
"device": {
"id": "device identifier",
"name": "device display name",
"platform": "platform identifier",
"identity": "BASE64URL(Ed25519 public key)"
},
"lan": {
"port": 28073,
"ephemeral": "BASE64URL(X25519 public key)"
},
"discovery": {
"timestamp": 1714000000,
"ttl": 300
}
}
}
The LAN signature payload is the following fixed-field JSON string:
{"id":"...","name":"...","platform":"...","identity":"...","lan_ephemeral":"...","nonce":"..."}
Receivers verify the Ed25519 signature before trusting the advertised identity and ephemeral key. Unknown fields are ignored unless they are required by a negotiated future capability.
Shared Secret Derivation
For a transfer between device A and device B:
secret_A = X25519(A_E_priv, B_E_pub)
secret_B = X25519(B_E_priv, A_E_pub)
Both devices derive the same shared secret without transmitting it.
The shared secret is then bound to the transfer context with HKDF. Current profiles use:
lan_file_key = HKDF-SHA256(shared_secret, info = "filie-file", length = 32)
cloud_file_key = HKDF-SHA256(shared_secret,
info = "filie-cloud-transfer:" || transfer_id,
length = 32)
Future profiles may derive separate metadata, file, and chunk keys from an intermediate session key:
session_key = HKDF-SHA256(shared_secret, info = "filie-session", length = 32)
file_key = HKDF-SHA256(session_key, info = "filie-file", length = 32)
meta_key = HKDF-SHA256(session_key, info = "filie-meta", length = 32)
Key-derivation labels are part of the protocol profile and must not be reused for unrelated purposes.
Chunk Encryption
Files are split into chunks. Each chunk is encrypted independently with AES-256-GCM:
box_i = AES-256-GCM-Encrypt(file_key, plaintext_chunk_i)
The serialized encrypted box is:
nonce || ciphertext || tag
The nonce is included with each encrypted chunk. Receivers reconstruct the AEAD box, authenticate it, and reject the transfer if authentication fails.
Chunk size and upload/download parallelism are implementation tunables. Changing chunk size does not change the cryptographic model as long as each chunk is authenticated and encrypted independently.
LAN Transfer Profile
LAN discovery uses multicast to advertise signed device envelopes. The current LAN profile uses:
IPv4 multicast: 239.0.19.69:25077
IPv6 multicast: ff02::1969:25077
Default local HTTP transfer port: 28073
The receiver exposes a local HTTP endpoint:
GET /device: returns the receiver device and LAN public agreement key.POST /accept: receives a signed transfer intent and prompts for local user approval.POST /upload: receives encrypted chunk frames for one file.POST /done: ends the accepted sender session.
The /accept body includes the sender signed envelope plus transfer summary:
{
"hdr": {
"nonce": "...",
"sig": "..."
},
"body": {
"device": {
"id": "...",
"name": "...",
"platform": "...",
"identity": "..."
},
"lan": {
"ephemeral": "..."
},
"transfer": {
"description": "10 photos",
"file_count": 10,
"total_bytes": 1048576
}
}
}
For /upload, each encrypted chunk frame is serialized as:
clear_len_u32_be || box_len_u32_be || aes_gcm_box
The request includes:
X-Filie-Sender-Id: sender device id
X-Filie-Filename: base64url(utf8(original filename))
The receiver accepts uploads only from a sender session that passed signature verification and local approval.
Cloud Transfer Profile
Cloud-assisted transfers use relay services for coordination and encrypted chunk storage. The relay may know transfer identifiers, device identifiers, file counts, chunk counts, chunk sizes, timing, and encrypted bytes. It does not receive plaintext, private keys, shared secrets, or derived transfer keys.
The current encrypted cloud mode identifier is:
x25519-aesgcm
A cloud transfer includes:
- Sender signed device envelope.
- Receiver signed device envelope or receiver device identifier.
- Sender and receiver X25519 ephemeral public keys.
- Transfer identifier.
- File descriptors such as file id, name, size, chunk size, and chunk count.
- Encrypted chunks stored or relayed as opaque bytes.
For upload, the sender derives:
shared_secret = X25519(sender_E_priv, receiver_E_pub)
file_key = HKDF-SHA256(shared_secret,
info = "filie-cloud-transfer:" || transfer_id,
length = 32)
For receive, the receiver derives:
shared_secret = X25519(receiver_E_priv, sender_E_pub)
file_key = HKDF-SHA256(shared_secret,
info = "filie-cloud-transfer:" || transfer_id,
length = 32)
If the receiver no longer has the private key corresponding to the advertised receiver ephemeral public key, the transfer cannot be decrypted.
Stranger Transfer Profile
A stranger transfer is a cloud-assisted transfer discovered through a short code. The short code is a rendezvous locator, not an encryption secret.
The relay uses the code to connect sender and receiver long enough to exchange signed device envelopes and public agreement keys. File encryption still uses the same X25519, HKDF, and AES-GCM pipeline. Compromise of the short code alone does not reveal file contents.
Retention Profile
The core protocol requires only that private agreement keys stay local. It does not mandate a specific private-key retention duration.
A deployment may choose a bounded retention profile for recent ephemeral private keys to support delayed delivery, offline devices, retries, and cold starts. This affects the security/usability tradeoff:
- Shorter retention reduces the amount of recent ciphertext decryptable after a device compromise.
- Longer retention improves reliability for delayed or offline delivery.
- Expired private keys should be deleted from persistent storage.
- Retention policy should be documented as an implementation or product security profile, not as a change to the wire protocol.
For public descriptions, it is accurate to say that Filie uses bounded local key retention when that profile is enabled. Avoid describing bounded retention as full perfect forward secrecy. It limits historical exposure, but retained keys can decrypt the ciphertext they cover if the endpoint is compromised while those keys are still available.
Security Properties
Filie is designed so that:
- Captured traffic does not contain plaintext file data.
- Captured traffic does not contain shared secrets or private keys.
- Relay/storage compromise does not reveal file contents without endpoint key material.
- Chunk authentication detects ciphertext modification.
- Device announcements bind identity keys to ephemeral agreement keys.
- Decryption of delayed transfers is possible only while the relevant receiver ephemeral private key is still locally available.
Non-Goals and Metadata
Filie does not hide all metadata by itself. Depending on the transfer path, a network or relay observer may learn:
- Source and destination IP addresses.
- Timing and duration of activity.
- Transfer identifiers.
- Device identifiers or pseudonyms.
- File counts, chunk counts, and byte sizes.
- Whether a transfer completed, expired, or was retried.
Network metadata reduction can be layered below Filie, for example with a VPN or multi-hop transport. That is separate from Filie's payload encryption protocol.
Filie also does not protect against:
- Malware or live compromise on the sender or receiver device.
- Malicious operating system components.
- Compromised application update channels.
- Users approving transfers from the wrong device.
- Weaknesses introduced by replacing the specified primitives with non-equivalent algorithms.
Post-Quantum Migration
The current X25519 key agreement and Ed25519 signatures are classical elliptic curve primitives. They are not considered resistant to a future cryptographically relevant quantum computer.
A post-quantum migration profile should use hybrid key establishment:
classical_secret = X25519(...)
pq_secret = ML-KEM.Decapsulate(...) or ML-KEM shared secret
hybrid_secret = HKDF-SHA256(classical_secret || pq_secret,
info = "filie-hybrid-session",
length = 32)
Transfer keys would then be derived from hybrid_secret rather than directly from the X25519 shared secret. Hybrid mode preserves compatibility with current classical security assumptions while adding protection against harvest-now, decrypt-later attacks if the post-quantum KEM remains secure.
A future identity migration may similarly use hybrid signatures, such as Ed25519 plus a standardized post-quantum signature scheme. Payload secrecy should prioritize hybrid key establishment first.
Versioning
Protocol profiles should be identified explicitly when serialized on the wire. Examples:
x25519-aesgcm
x25519-mlkem-aesgcm
Receivers must fail closed when a transfer requests encryption but the relay or peer does not return the expected encryption profile. Unsupported cryptographic profiles must be rejected rather than silently downgraded.
Open Protocol Statement
This document describes Filie's application-layer end-to-end encryption protocol. Filie uses documented message formats and standard cryptographic primitives rather than secret proprietary cryptography.
The control plane is human-readable JSON. Discovery, identity, transfer setup, and public key material can be inspected directly on the wire. File contents are not carried in plaintext; they are carried as opaque authenticated-encrypted chunks. This keeps the protocol open and auditable while protecting transfer contents and detecting payload tampering.