Security whitepaperSkiff uses the latest in privacy, cryptography, and decentralization to keep your work and personal data private and truly owned by you. We explain how Skiff's platform guarantees your privacy at a technical level below.Last updated February 2023
End-to-end encryption of all sensitive information
The contents and certain metadata (including title, time created, and last modified date) associated with every document created or uploaded by a user is only visible to the user or shared collaborators.
Resistant to man-in-the-middle attacks
Even without a fully trusted communication channel between the server and clients, our model will never reveal email subject, email content, or document title, contents, and other information.
Resistant to user abuse attacks
We are particularly sensitive to user abuse as a threat vector. One user abuse attack includes sharing unwanted information or documents with a particular target user.
Resistant to impersonation attacks
Our model must be resistant to impersonation of any of the parties (server or clients). It should also inhibit impersonation of other users
Makes phishing difficult
Skiff seeks to prevent adversaries from compromising user accounts even if their password is compromised, including using 2FA, and and/or hardware tokens.
Building a usable, responsive, and intuitive product with these security properties is critical to ensuring that users do not switch to less-secure alternatives due to poor usability.
Overview and encryption protocolsPublic-key authenticated encryption allows us to securely and privately share access to end-to-end encrypted documents in our security model. Under this schema, each user is issued a long-term public signing key and a medium to long term public key for encryption. Each public key is associated with a corresponding private key generated using Curve25519. We use tweetnacl-js as our encryption library for both asymmetric public-key authenticated encryption (tweetnacl.box) and secret-key authenticated encryption using xsalsa20-poly1305 (tweetnacl.secretbox). Both algorithms ensure both confidentiality and authenticity of encrypted data (AEAD). While a user’s encryption and signing public keys can be freely shared and used to securely send or verify information, all private keys - which can decrypt information or generate signatures - must be kept private. We discuss how this is done in the following section
Login, creating accounts, and private key storageFor a new user Alice, our account creation and login system is designed to:
- Keep Alice’s private keys safe
- Ensure sensitive information - such as Alice’s password and private keys - are never sent beyond her browser window, and
- Resist brute-force and dictionary attacks.
- Bob enters his email and generates a secure password (more than n digits, upper/lower case letters, numbers, and special characters). Random encryption and signing keypairs are generated (tweetnacl.js) for Bob’s account in-browser.
- On the browser, we run Argon2id to derive a symmetric key from Bob’s password. Using HKDF, this symmetric key is used to generate one symmetric key for login (using the Secure Remote Password protocol), and another symmetric key for encrypting Bob’s secrets (i.e. private keys). This second key is called Bob’s password_derived_secret.
- We use Bob’s password_derived_secret to encrypt sensitive data associated with Bob’s account; this encrypted data is called Bob’s encrypted_user_data. This includes Bob’s private keys but not his password. This encrypted information is stored by our server but can only be decrypted with Bob’s password_derived_ secret. The next time Bob logs in, Bob downloads his encrypted_user_data from the server, then decrypts the encrypted_user_data in-browser by using the password_derived_secret. The password_ derived_secret never leaves the browser.
Account recovery and password changesWhen users forget their password, it’s convenient for them to have a way to recover their account and reset their password. This is achieved using a recovery key (a symmetric key similar to the password_derived_secret). A user can enable account recovery in their settings, which generates a recovery key. The recovery key is used to encrypt the user’s private data (i.e. private keys); this encrypted user data is stored by Skiff but inaccessible. When a user requests account recovery, their identity is first verified through email. The server sends an email to the user containing a random eight-character alphanumeric passcode which they can use to prove access to their email account. After this step, the user enters their email, recovery key, and a new password. The client hashes the recovery key, which is sent to the server. The server checks if the hash matches the stored recovery key hash, and that the client retains the correct email code. If both match, the server sends the encrypted user data to the client, which then decrypts it with their recovery key. Note that storing a hash of the recovery key is not like storing a hash of a user’s password; while a password may be predictable and reused, the recovery key is a randomly generated symmetric key. From this point, the process is similar to choosing a new password when an account is created - a password_ derived_secret is derived from the new password, which is then used to encrypt the user’s private data, and the encrypted user data is uploaded to the server, replacing the previous data encrypted with the old password_derived_secret. In future implementations, account recovery can be accomplished using n-of-m Shamir Secret Sharing to maintain endto-end encryption while increasing usability. For example, using 2-of-3 secret sharing, one secret share could be stored in the user’s device, another stored by Skiff’s server, and another provided for “paper” storage. In this model, usability may be significantly higher for many use cases.
OverviewSkiff Mail extends the Skiff Workspace to enable privacy-first and end-to-end encrypted communication. This section breaks down different cases for sending and receiving messages on Skiff Mail, including to and from external email addresses.
Sending from Skiff Mail to Skiff emailSending an email from one Skiff address to another is very similar to sharing a Skiff document with another user. Consider the scenario where Alice wants to send an email email_a to Bob, where both Alice and Bob are Skiff users (say [email protected] and [email protected]). When Alice clicks “send” in her Skiff Mail client, Alice’s Skiff client generates a random symmetric key sym_key_email_a to encrypt the email subject and content corresponding to sym_key_email_a. This symmetric key sym_key_email_a is subsequently encrypted with Alice’s and Bob’s encryption public keys for future access, as with a document shared on Skiff’s collaboration platform. Now, as in Skiff’s collaborative workspace, the receiver can log in and decrypt the email’s symmetric key to gain access to the sent message.Under this model, any email sent and received via Skiff Mail is completely end-to-end encrypted and private to Alice, Bob, and any other recipients. No third party (not even Skiff) ever sees or processes the message content.
Sending from Skiff Mail to an External emailWhen Alice sends an email email_b from her Skiff Mail client to an external email address, Alice’s Skiff client will still generates a symmetric key sym_key_email_b and encrypt this key with Alice’s public key for future access. However, in order to send the mail to an external, unencrypted email address, Alice’s client also encrypts this email with the public key of a decryption service that temporarily processes this mail for external receipt.To send the email email_b externally to Charlie (say charlie@ external.com), Alice’s Skiff client now encrypts email_b with the public key of the decryption service pubkey_decrypt. This decryption service ephemerally decrypts the message email_b, composes outgoing MIMEs needed to send email_b to Charlie at [email protected], and sends email_b message to the external email address. Now, Charlie - a non-Skiff recipient - can read Alice’s sent mail. The key used by the decryption service to send this message externally is discarded and deleted, leaving no way for a third party (not even Skiff) to access any sensitive information inside email_b in the future. As in the Skiff-to-Skiff mail case, Skiff does not store an unencrypted copy of this externally sent mail.
Email receiving - External to Skiff MailNow, when loading her Skiff inbox, Alice can decrypt the encrypted copy of email email_d in order to read the message. The encryption service discards and deletes its initial randomly generated copy of sym_key_email_d , now ensuring that every message inside Alice’s inbox remains end-to-end encrypted and completely private to her.
This encryption step - taking the unencrypted, external email email_b and transforming it into an encrypted message on Skiff Mail - ensures that Skiff never stores copies of users’ unencrypted mail, even when sent by an external service.
Skiff Pages and Drive
OverviewEvery document is associated with a short-term symmetric session_key as well as an asymmetric “hierarchical” keypair. The session_key is used to encrypt all document contents and metadata that are stored on the server. In order to support real-time collaboration and simple sharing mechanisms, all collaborators - say Alice and Bob - have access to the same session_key. However, because Alice and Bob have different asymmetric key pairs, they each have unique encrypted copies of the same session key (encrypted with public_key_Alice and public_key_Bob, respectively). Using this symmetric session_key, we can outline processes for creating, editing, and sharing documents. In the following section, we share more about how a document’s hierarchical key can be used for constructing a scalable filesystem out of many thousands of documents.
Real-time collaborationReal-time collaboration among shared users on a document is end-to-end encrypted using the document’s session key. On Skiff, conflict resolution is performed using a CRDT, which allows each collaborator to maintain an in-browser copy of the document and perform change resolution as live document updates are received from other users. To initiate a collaboration session using the CRDT, two shared users open the document and create a WebSocket connections to a shared WebSocket “room” allowing messages to be passed to other participants. They include the unique identifier of the document for collaboration. At this point, both users begin broadcasting end-to-end encrypted updates to the CRDT through this WebSocket connection to other users listening for collaboration updates. Each user decrypts the CRDT updates (using the document symmetric key) and applies these updates to their local copies of the document data structure. After applying updates, all collaborative users arrive at a final version of the shared document.
Link sharing a documentLink sharing is a critical usability feature for modern collaboration. Unlike all link sharing schemes in use by collaborative products today, Skiff’s link sharing mechanism maintains end-to-end encryption such that not even Skiff can gain access to a document’s URL. In this section, we discuss “end-to-end encrypted links." These links enable sharing single pages, embedded files, and entire recursive subtrees of documents, such as wikis, blogs, or websites. Skiff’s end-to-end encrypted links store information in the URL that remains private to the client (using a URL fragment) and employ an authentication technique extremely similar to the user login method documented above. In order to generate a sharable link for a document, d2, Alice:
- Generates a random key link_key_d2, and encrypts session_key_d2 with link_key_d2, and encrypts the link_key with session_key_d2. It is critical that Alice encrypts the link key with the session key so she can recover the document link when redownloading the document (for example, after logging out and logging back in).
- Using link_key_d2 as a “password," Alice generates a salt and verifier used for Secure Remote Password. As in user account creation, the salt, verifier, and encrypted keys are stored by the server. However, it is impossible for the server to decrypt the link_key or the session_ key.
- Parses the URL to extract link_key and docID
- Performs the SRP login process to request the salt and send a proof back to the server, which responds with the encrypted session_key_d2
- Bob then decrypts session_key_d2 with link_key_d2. At this point, Bob can download and read document d2.
- If Alice has enabled editing for the link, Bob sends a copy of session_key_d2 encrypted with Bob’s public key. The server stores this key and a new permission entry on d2 for Bob to access in the future.