This is a design project of CS 161 at UC Berkeley. The goal is designing an end-to-end encrypted file sharing system by using cryptos we learned in class. I designed this system by myself.

In order to design this system, we have to find ways to secure three parts of this system. The first part is how to secure users’ credentials, the second part is how to secure files content with efficient appending, and the third part is how to share securely. There are eight methods I have to finish, \(InitUser\), \(GetUser\), \(StoreFile\), \(AppendFile\), \(LoadFile\), \(ShareFile\), \(ReceiveFile\), and \(RevokeFile\).

  • \(InitUser\) - this method create an user account and store all necessary information of an user on database.

  • \(GetUser\) - this method can be called while logging in an user, and it will retrieve and decrypt all necessary information of an user.

  • \(StoreFile\) - this method is called when an user is trying to store a file.

  • \(AppendFile\) - this method is called when an user is trying to append something to a file.

  • \(LoadFile\) - this method is called when an user is trying to access a file’s content.

  • \(ShareFile\) - this method shares a file from a user who has access to that file.

  • \(ReceiveFile\) - this method is called by the file sharing receiver which will give the receiver full access to a file.

  • \(RevokeFile\) - this method can only be called by the file owner to revoke a user’s access to a file, and all users who got access from this revoked user will no longer can access this file.

There are two databases provided. One is \(DataStore\) and the other is \(KeyStore\). Each one is a dictionary structured database with uuids as keys. \(DataStore\) can be compromised, but \(KeyStore\) is always assumed secure.

The crypto methods we have access to include RSA, Digital Signature, Hash, HMAC, and Symmetric Encryption. We also have a Passward Key Derivation Function which generates one key, a Hash Based Key Derivation Function which generates multiple keys, and a Random Bte Generator.

My Design

The system designed by me fully relied on users’ passwords. Since each password is only known to that user, all of my keys can be assumed as secure if I derive them from the password. Below I will address how I make all three parts of this system secure.

Users

The first part is storing users’ credential securely. Each user would have a User structure which contains its username, rsa_private, ds_sign, and file_key. The file_key is derived from the user’s password and will work as an universal file Ini symmetric enc / dec key, and this key is only known to the user. The User structure will be encrypted using another key derived from user’s password and sign.

User’s password is stored with salting and slow hashing seperately from the User structure, so one would verify the password before touching the User structure. The password will be signed before storing.

File Storage

When storing a file, I store three parts of information. The first part is the file Ini, the second part is the file metadata, and the third one is the file content block.

File Ini contains a uuid points to the file metadata, the file symmetric key, the file HMAC, and the file owner who initially created this file. This is encrypted by user’s own file key which is derived from user’s password, and the file Ini can be only encrypt/decrypt/signed by this user. The uuid of file Ini is generated from username and filename.

File metadata contains a list of uuids point to each file content block, the access tree of this file, and a Share map which maps from each sharing user’s username to his own file Ini’s uuid. The uuid of file metadata is randomly generated.

File content block is an encrypted and signed using file HMAC file data block. The uuid of each file content block is also randomly generated.

Both file metadata and file content block will be encrypted using the file symmetric key stored in file Ini, and signed using the HMAC.

Besides, in order to support a fast append, my design uses multiple storage blocks on file content instead of just one block for each whole file. Everytime AppendFile() is called, the file Ini will be first retrieved and then the file metadata. The signature will be verified first and everything will be decrypted after verifying. Then metadata will be updated with the appended block uuid, re-signed, and re-encrypted after finishing the appending.

When appending the file content, the only thing required to do is creating a new file block structure for the new appending content. Then encrypt the new content and signed, then only push this block and the new file metadata block to the server. So, each time a user is loading a file, he is loading a list of uuids stored in file metadata. All these uuids point to each file content block, and combining them together will give a user the whole file.

File Sharing

General idea on sharing in my design is passing the file Ini which contains all information of a file to the recipient. When a user shares, he first retrieve his own file Ini, verify and decrypt, then re-encrypt using the recipient’s RSA public key, next signed and send this as the magic string.

After the recipient receives the magic string, what he actually receives is the file Ini which contains information about where to find the file metadata, how to encrypt/decrypt/sign the file, and who is the original owner. The recipient would have the power to find, append, and load the file with these information.

When a user tries to revoke, he first retrieve the file Ini and check whether he is the owner of this file. After checking, if he is indeed the owner, he would retrieve the file metadata block. Next, he will get a list of users he has to revoke from the access tree, and remove their entries from the sharing list.

Now, in file Ini, he re-generates new uuid for the file metadata, new random file symmetric key, and new random file HMAC. Next, I have a wrapping struct built for this part outside of file Ini contains an Update section. The owner would now put the new file Ini encrypted using each still sharing user’s RSA public key at this update section by looping through the updated sharing list. Additionally, the owner can also re-generate new uuid for all file content block and update the uuids list in the file metadata to make sure the user who is revoked can never access any part of this file.

In order to make this update section work, here is the logic. The file Ini can only be encrypted/decrypted/signed by that user only, so the user would always first verify and decrypt the file Ini, then use the file owner stored in file Ini to get the owner’s DS verify key to verify the Update section if it is not nil. Only the owner can revoke, so anyone put and signed something at the Update section would be wrong.

After the revoken, every user still on the sharing list would still have the power of editing this file as before, but revoked users would lose the information of the file metadata, even all file content blocks.