How Pontile protects your documents.
In a few lines: how encryption works, what we see and what stays out of our reach.
How it works
How it works, in 4 steps.
It all happens in your browser, before a single byte reaches our servers.
Your password
From your password the browser derives the keys of your account. The password never leaves the device.
For engineers
Argon2id (64 MiB, 3 iterations), then HKDF-SHA-256: one key is used to log in, the other encrypts the master key. The server only receives a derived value.
Your keys stay on your device
Your personal keys are created in the browser. The server only gets them locked with keys that only you know.
For engineers
An X25519 keypair to receive keys and an Ed25519 keypair to sign; the private halves are encrypted with XChaCha20-Poly1305 under the master key.
Every file locked before it leaves
Every file is encrypted with a fresh key. Our servers only receive unreadable bytes.
For engineers
XChaCha20-Poly1305 in 1 MiB segments, one key per version; the manifest is signed with Ed25519 and integrity is checked with BLAKE2b-256.
Only the people you invite reopen it
Inviting someone means handing them the key, locked for them alone. Remove them and the keys change.
For engineers
The section key is sealed to the invitee’s X25519 public key (sealed box); every grant is an Ed25519-signed record, checked up to the owner.
Keys
One key inside the other.
Each key opens only the one below it: whoever holds the key of a section cannot read the others.
- PasswordOnly you know it
- Personal keysStay in your browser
- Hub keyNames of the sections
- Section keyChanges at every revocation
- File keyNew for every version
For engineers: all the keys
- PWK · Password keyArgon2id(password, salt)Never stored
- AK · Authentication keyHKDF(PWK, “hub-v1/auth”)Only an HMAC on the server
- KEK · Key encryption keyHKDF(PWK, “hub-v1/kek”)Never stored
- MK · Master key32 random bytes at sign-upEncrypted with the KEK and, separately, with the RK
- RK · Recovery key32 random bytes, given to the user as a codeNever stored
- IEK · Identity encryption keypairX25519, receives hub and section keysPrivate half encrypted with the MK
- ISK · Identity signing keypairEd25519, signs invitations, uploads, eventsPrivate half encrypted with the MK
- HK · Hub key32 random bytes, common hub metadataSealed for every member
- SK · Section key, per epoch32 random bytes, new at every rotationSealed for every member of the section
- DK · Deposit keypair, per epochX25519, uploads without read accessPrivate half encrypted with the SK
- FK · File key32 random bytes, new for every versionWrapped with the SK (or sealed to the DK)
- MDK · Metadata keyHKDF(FK, “hub-v1/meta”)Never stored
- NK · Folder key32 random bytes, new at every changeWrapped with the SK
- OK, OEK, RQK · Organizations and requestsOrganization key, its X25519 keypair, the key of each requestSealed only to members or recipients
Metadata
What we see, what we don’t.
To run the service the server knows some information. Not the content.
We see
- Users’ emails and public keys
- Who is a member of which hub and section, with which role
- How many files there are, their encrypted size and when they change
- IP addresses, for 30 days at most
We don’t see
- The content of the files
- The names of files, folders, sections and hubs
- Comments, reminders and request outcomes
- The keys to read
Limits
What it cannot protect.
No encryption protects against everything. Here are the limits, stated up front.
For engineers
The cryptographic primitives.
With the release we will publish the code of the app that runs in your browser: that is where encryption happens, and where anyone will be able to verify it.
Show the table of primitives
| Function | Algorithm |
|---|---|
| Key from the password | Argon2id v1.3 (RFC 9106): 64 MiB, 3 iterations |
| Subkeys | HKDF-SHA-256 (RFC 5869) |
| Data encryption | XChaCha20-Poly1305, authenticated encryption |
| Keys for a recipient | X25519, sealed box |
| Signatures | Ed25519 (RFC 8032) |
| Hashes and key log | BLAKE2b-256, Merkle tree (RFC 6962) |
Standard primitives only, from libsodium or equivalent implementations.
Questions about the protocol?
We are happy to answer engineers, lawyers and auditors.