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:

The protocol does not attempt to protect plaintext from a device that is already compromised before encryption or after decryption.

Terminology

Cryptographic Primitives

The current protocol profile uses:

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:

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:

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:

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:

Non-Goals and Metadata

Filie does not hide all metadata by itself. Depending on the transfer path, a network or relay observer may learn:

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:

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.

View source Markdown