owned this note
owned this note
Published
Linked with GitHub
Sunbin Kim and Cole Smith, Friday November 1
# CS161 Proj 2: An End-to-End Encrypted File Sharing System
## Section 1: System Design
1) How is each client initialized?
A client is initialized with a struct `UserHolder` that contains an encrypted `User` struct (symmetrically encrypted with the password as the key) as well as a hash of the password. A UUID is generated for this object and it is stored in the datastore. The UUID and username are then placed in a map in the datastore so they can be accessed in `GetUser`. When getting a User, we will retrieve the `UserHolder` struct and first check if the hash of the inputted password matches the stored hash of the password. If they match, we use the password to decrypt the `User` struct.
The `User` object will contain the username, the user's private RSA key, the user's DSA signing key, as well as a UUID of a dictionary of file UUIDs with filenames as keys.
2) How is a file stored on the server?
Files will be stored on the server with a `FileHolder` object that contains a link to the last chunk (4kb) of a file encrypted with a file specific symmetric key as well as a hash of the decrypted file. This allows us to check if the file has been altered by hashing the decrypted chunk and comparing it to the stored hash. Each file chunk contains the UUID of the previous chunk, allowing us to traverse backwards and build the file incrementally while checking that it has not been altered. The `FileHolder` object also contains a map of usernames to RSA encrypted versions of the symmetric key for all users with access to the file.
3) How are file names on the server determined?
The keys for the files in the DataStore will be random UUIDs which will point to the `FileHolder` for the file. The UUIDs and corresponding filename will be stored in an encrypted user-specific map object so that a user can later access it.
4) What is the process of sharing a file with a user?
To share a file with another user, we decrypt the symmetric key for the file using the user's private key. We then encrypt the symmetric key using the public key of the target user and add it to the map of usernames to encrypted keys in the `FileHolder`. Finally, we send the target user a magic string which contains the UUID of the `FileHolder` for the file enncrypted with their public key, as well as a signature for authenticity.
5) What is the process of revoking a user’s access to a file?
To revoke access, we remove the target user's name/encrypted key from the map in the `FileHolder`. Then, we re-encrypt the file with a new symmetric key and RSA encrypt this new key for each user who still has access. When the revoked user attempts to load the file, they will therefore be unable to decrypt it while the users who retain access will still be able to do so.
6) How were each of these components tested?
- User -
We test to ensure that the user files persist correctly in the datastore and can be accessed again through `GetUser`. We also test to ensure that the user objects are updated correctly after new files are shared/added.
- Storage -
We tested if the file is stored correctly by first storing the file and then loading it to see if the files match. For appending, we check if the file was tampered before we append and store.
- Sharing -
We tested multiple aspects of sharing. First, we check the validity of the user who participate in sharing. We test sharing with nonexistent user, nonexistent file, and/or receiving from a wrong user. We also test trying to receive file with wrong magic string. We also test trying to recieve file with the old magic string after the access is revoked.
- Revoking -
We tested revoking user after we share. Then we checked if the revoked user can still access the file by loading and appending because they shouldn't be able to load or append. We also checked revoking on nonexistent files/users. Finally, we make sure that they can't still access the file through direct UUID access (explained below).
## Section 2: Security Analysis
1) Access Revoked File Directly Through Datastore
In this case, we imagined that a user with shared access to file F may user a malicious client to store the UUIDs of the file chunks or the `FileHolder`. Therefore, even after their access is revoked, they could try to access the file directly through the datastore. To protect against this, we added measures to re-encrypt the file after access to anyone is revoked. While the malicious user may still be able to access the objects in the datastore, they will be unable to read them as have encrypted them all with a new symmetric key. We also make sure to encrypt and store the symmetric key using the RSA public keys of all users who should still have access so that they can access the decrypt the file.
2) Tamper
In this case, we ensure that a malicious client/server cannot edit a file that is stored within the database. We test if a file has been tampered when we load the file because that's when we can check if the file has been altered or not. First, we test when the same user that stored the file tries to load the file after it has been tampered. Second, we test if the file is tampered before a user tries to append to the file because we do not want to append or store the tampered file. Lastly, we check if the file is tampered after sharing and before receiving the file to make sure that the shared user doesn't receive or load a tampered file.
3) Misuse Magic String/Generate Fake Magic String
In these cases, a malicious user uses fake magic strings or misuses acutal magic strings. In the first case, a user tries to use a magic string meant to be shared with another user. We prevent this by encrypting the magic string with the public key of the designated user. In the next case, a user attempts to use an old magic string to access a file even though their access has already been revoked. We prevent this by re-encrypting the entire file with a new symmetric key, so even though the user can access the `FileHolder` with the old magic string, they cannot access the file. Finally, there is the case where a user attempts to generate a fake magic string. This is prevented by attaching a DSA signature to the magic string that can be verified by checking the signature with the verification key of the user who shared it to ensure authenticity.