Storing files on a server and sharing them with friends and collaborators is very useful. Commercial services like Dropbox or Google Drive are popular examples of a file store service (with convenient filesystem interfaces). But what if you couldn’t trust the server you wanted to store files on? What if you wanted to securely share and collaborate on files, even if the owner of the server is malicious?
In this project, you’ll use the cryptographic tools we’ve taught you to build a file storage client that’s secure and efficient despite storing all of your data on a malicious storage server.
Your task is to design an encrypted file store. This file store can be used to store your own files securely, or to share your files with other people you trust.
Your implementation should have two properties:
Confidentiality. Any data placed in the file store should be available only to you and people you share the file with. In particular, the server should not be able to learn any bits of information of any file you store, nor of the name of any file you store.
Integrity. You should be able to detect if any of your files have been modified while stored on the server and reject them if they have been. More formally, you should only accept changes to a file if the change was performed by either you or someone who you have shared access to the file with.
Note on security parameters. It is sufficient that these properties hold with very high probability (i.e., no better than brute forcing the key being used). We are not requiring that it is impossible for an adversary to do something malicious (e.g., decrypt or modify data) because that would not be possible.
This first part is due early!
Question 1 Simple Upload/Download
Implement a file store with a secure (but possibly inefficient) upload/download interface. For Question 1, your task is to implement the methods upload and download. The methods must ensure the following properties hold:
- Property 1 (Benign Setting) download(name) returns the last value stored at name by the owner, or None if this file does not exist, when not under attack by the storage server or another user.
- Property 1 (Attack Setting) download(name) returns a value stored previously at name by the owner, or None, if under attack by the storage server or another user. It must raise an IntegrityError if the value stored at name was ever modified by anyone (other than the owner) to a value that was not previously stored.
- Property 2 upload(name, value) places the value value at name so that future downloads for name return value. It may return False if a malicious server makes the upload fail, and should return True otherwise. No person other than the owner of name should be able to learn even partial information about value or name with probability better than random guesses.
You may assume file names are alphanumeric (that is, they match the regex [A-Za-z0-9]+). File names will not be empty. This will be the case for all parts of this project. The contents of the file can be arbitrary: you must not make any assumptions there. You may assume usernames consist solely of lower-case letters ([a-z]+).
You do not need to implement any capacity to share files between users, at this stage. We have provided an implementation of the storage server—do not change it. You won’t need the public key server for this part.
Note that we require you protect the confidentiality and integrity of both the contents of the file you store and the name it is stored under. A malicious storage server must not be able to learn either, or change them. The length of the file and the length of the filename don’t need to be kept confidential.
When used in a non-adversarial manner, different users should be allowed to have files with the same name: they should not overwrite each other’s files. An adversary may be able to overwrite a user’s valid data, but any changes should be reported as an IntegrityError.