- Encryption algorithm: aes-256-gcm
- Hashing algorithm: sha512
- Key derivation algorithm: pbkdf2
- The server receives the following from the client:
- Username: user-specific alphanumeric string
- Salt1: user-specific random 64-bytes
- Salt2: user-specific random 64-bytes
- Derived key: from the password and salt1 a derived key is producted with pbkdf2, with {A} number of iterations, then that and salt2 are piped into pbkdf2, with {B} the number of iterations, to produce the actual final key
- If the user doesn't know it already they ask the server for their salt1
- The server receives the following from the client:
- Username: the same string used when signing up
- Partially derived key: from the password and salt1 a derived key is producted with pbkdf2, with {A} number of iterations
- The server does the following:
- Derived key: the partially derived key and salt2 are piped into pbkdf2, with {B} number of iterations, to produce the actual final key
- If the saved and computed derived keys match, according to a comparator function safe against timing attacks, then the user is successfully authenticated, otherwise they are not
-
The server receives the following from the client:
- Everything necessary to be authenticated
- A concatenated buffer produced like this:
- Initialization vector: file-specific random 16-bytes
- Salt: file-specific random 64-bytes
- Derived key: from the password and salt a derived key is produced with pbkdf2, with {C} number of iterations
- Encrypted buffer: the clear file buffer, initialization vector, and derived key as used to produce the encrypted file buffer
- Auth tag: the auth tag is fetched from the cipher
- Concatenated buffer: initialization vector, salt, tag and actual encrypted file buffer are contactenated and that's what the server receives
-
The client receives the following from the server:
- Unique ID of the uploaded file
-
The server receives the following from the client:
- Everything necessary to be authenticated
- Unique ID of the file to download
-
The client receives the following from the server:
- The concatenated buffer
-
The client does the following:
- Extracts initialization vector, salt, tag and actual encrypted file buffer from the concatenated buffer
- Does basically the inverse process for decrypting the encrypted file buffer
- When changing password both the client and the server start crying, then the server sends the client every single file that needs to be decrypted with the old password and encrypted with the new password, the client for each file downloads it, decrypts it with the old password, encrypts it with the new password, and uploads it back to the server. Once the re-encryption process is complete the derived key for authentication is uploaded too and that's it.
- {A}, {B} and {C} need to be chosen appropriately, not too low but not too high either.
- Sending salt1 to anybody who asks for it sounds sketchy, but it should be ok, right? 🤔
- Changing password is such a pain in the ass, and I don't think it's something that can be done any differently, privacy has a cost.
- For performance reasons it would be better to give the client a temporary token for authentication once they authenticate themselves, otherwise we'd be computing the same keys over and over again.
- Using a different salt for each file may be a slight performance problem, using the same salt for each file would be faster as the key could be pre-computed, it's probably worth it to use a different hash for each file as that's much safer though.
- Missed anything major? Any major flaw?