Note: The terms, policies, etc. outlined below are only applicable to the YeetFile service hosted on yeetfile.com, as well as the code as it exists in the repository (available on GitHub or SourceHut).
If you are not using yeetfile.com or hosting the service, these terms cannot be guaranteed.
Security
The following document outlines how the different actions in YeetFile are performed in a secure manner.
Accounts
Signup
Creation of an account can be done by a user providing their email address or opting to only use the YeetFile-generated account ID as the user's identifier. Along with the user's identifier (email or account ID) the user must also choose a password. The identifier and password are used to generate the User Key using Argon2 with the password as the payload and SHA-256 hash of the identifier (email or account ID) as the salt.
After the User Key is generated, the key itself is put through another round of Argon2 with the User Key as the payload, and the user's password as the salt, in order to generate a "Login Key Hash". The Login Key Hash is then sent to the server, along with a newly generated RSA keypair with the Private Key encrypted by the User Key using AES-GCM.
Once the signup request reaches the server, the server validates the signup
either via email verification (for email signups) or through a simple 6-digit
"captcha" displayed to the user. If this validation step is successful, a new
entry is added to the users
table, with the user's ID, encrypted private key,
plaintext public key, and bcrypt-encrypted Login Key Hash.
Successful signups are converted to successful logins, which follow the same logic as below.
Login
To log in, a user provides their identifier (email or account ID) and their password. These two values are used to generate their User Key using Argon2, with their password as the payload and their identifier as the salt.
Once the User Key has been generated, the key itself is put through another round of Argon2 with the User Key as the payload, and the user's password as the salt, in order to generate a "Login Key Hash". The Login Key Hash is then sent to the server to validate their login attempt. The server compares the Login Key Hash against the bcrypt-ed value stored in the user table, and validates the login attempt if there is a match.
If the login attempt is valid, the user's Public Key and encrypted Private Key are returned to the user. The Private Key is then decrypted using the User Key and re-encrypted with a unique session-specific key before getting stored in IndexedDB (web-only). If the user is using the CLI, their key pair is encrypted using a random value that is displayed to the user before writing the encrypted key values to a file in the user's YeetFile config directory. This value can be stored in the user's .bashrc (or similar file) for convenience, but care should be taken to regularly log out or otherwise revalidate their CLI session.
For both web and CLI, users have the option to provide their own session-specific vault password that will be required to be provided each time a user opens their file or password vault. If a password is provided, the session-specific key value mentioned earlier is used as the salt for an Argon2 key generated using the password the user provides. This Argon2 key is then used to encrypt the user's private key at rest.
Two-Factor Auth
YeetFile allows setting up TOTP based 2FA through both the web and command line. A set of one-time recovery codes are provided upon successfully enabling 2FA, which are hashed using bcrypt and stored in the database. When a recovery code is provided in place of a TOTP code, the code is compared against the list of bcrypted hashes in the database. If there's a match, the recovery code is removed from the database.
Losing Account Password
Since the server never receives a user's true password, and since YeetFile uses zero-knowledge encryption, password recovery is not possible.
Your password is used to generate your unique User Key, which is used to encrypt your private key. Without your password, you cannot decrypt your private key, meaning you also cannot reset your password either, even if you have an email registered.
To avoid getting locked out of your account, it's recommended to set a password hint either when signing up or at any point after signup from the Account page. The password hint is encrypted and can be sent to the email address associated with your account if you ever lose your password.
Note that since the server needs to be able to send the password hint to the user's email, the hint needs to be readable by the server. The server stores the hint encrypted using a key that is unique to the server, and is only decrypted when the user requests their password hint.
Users who do not have an email associated with their account cannot set a password hint (and therefore have no way of recovering a lost password).
YeetFile Vault
Files / Passwords
Uploading a file or password entry to YeetFile Vault involves the following steps:
- Generate a unique key for the item, encrypted with the current folder key
- Upload the file metadata* to the server, along with the encrypted item key
- Split the item into chunks (only applicable to files)
- Encrypt each chunk with the file key, and upload the chunk until the file is complete
The "current folder key" depends on where in the vault the item is being uploaded. If the item is being uploaded to the root level of the Vault (not within a folder), the "folder key" is the user's public key. If the item is being uploaded to a subfolder, the "folder key" is the current subfolder's unique key, which is encrypted by its parent's folder key. To access subfolders, a "key sequence" is returned by YeetFile, which is the sequence of folder keys required to decrypt before the current folder's key. For example:
Root/FolderA/FolderB/FolderC/MyItem
Accessing MyItem would return a key sequence of:
FolderA-Key
(decrypted by user's private key) -> FolderB-Key
(decrypted by
FolderA-Key) -> FolderC-Key
(decrypted by FolderB-Key).
The decrypted FolderC-Key could then by used to decrypt MyItem
's key.
* File metadata includes the name of the file (encrypted with the file key), the file size, and the number of chunks for the server to expect. Password metadata includes the serialized password entry (still encrypted with the item key before uploading).
Folders
Creating a folder in a YeetFile vault involves the following steps:
- Generate a unique key for the new folder, encrypted with the current folder key
- Inputting the name of the folder
- Uploading the encrypted name of the folder to the server along with the encrypted folder key
The encryption of the new folder's key is the same process as described in the Files section above, where every folder's key is encrypted by its parent's folder key until the root level of the vault, where everything is encrypted with the user's public key.
Sharing
Vault items and folders can be shared with other YeetFile users by using the "Share" button in a item/folder's action menu. Another user's identifier must be provided (their email or account ID), and if the user exists, their public key is returned to the user sharing the content.
The other user's public key is then used to encrypt the key of the item/folder to be shared, and a new entry is added to the vault database table containing a new item/folder ID for the recipient user, with the item/folder added to the root level of their vault.
Items shared with a user cannot be further shared by the recipient user. True ownership of a item/folder is determined by checking that a item/folder ID matches its "reference ID" in the database, and that the entry's owner ID matches the current user's ID.
YeetFile Send
Sending a file differs from Vault uploads by adding new metadata fields, and removing the association of a user ID with the upload.
The metadata fields required for using YeetFile Send are:
- The file expiration (up to 30 days)
- The number of times a file can be downloaded (max 10)
- A password for the file (optional)
The password is used along with a randomly generated 32-byte salt in 600K rounds of PBKDF2 to create a unique key for encrypting the file's name and contents.
Metadata for the file, including the encrypted filename, the file size, number of chunks, the expiration, number of downloads, and the salt generated for the key, are uploaded to the server.
After the metadata has been ingested by the server, the file is split into chunks and the unique file key is used to encrypt each individual file chunk until the file is finished uploading. When the file is finished uploading, a download link will be displayed to the user. This is only displayed after upload is irrecoverable after navigating away from the page or resetting the form. The link looks similar to the following:
/send/file_8z74nn1spdni
This link is then formatted (by the client) with the encoded key (if no password was provided) or the encoded salt (if a password was provided) that the client generated before uploading:
/send/file_8z74nn1spdni#jMKL0xl_-nZX5val3f1UhFQoecjeVckQXUcIscdTd0g
Because URL fragments (contents after the #
character) are not sent to the
server, the key or salt can be included in the link without being seen by the
server. This way only the user and the recipient the user shares the link with
are able to download the file.
When a user attempts to download the file, the URL fragment will first be used as the actual key. If decryption fails, the fragment is assumed to be the salt, and the user is prompted for the password.
Changing Password
When a user updates their password, they generate a new User Key using the new password, and use that updated key to encrypt their Private Key. They also generate a new Login Key Hash using the new key and their new password, and send both the updated Private Key and updated Login Key Hash to the server.
Logout
Logging out removes the user's keys from IndexedDB (web) or the YeetFile config directory (CLI) and invalidates the user's session.