Link Search Menu Expand Document

3. Design Requirements

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

3.1 Usernames and Passwords

  1. Usernames
    1. The client SHOULD assume that each user has a unique username.
    2. Usernames are case-sensitive: Bob and bob are different users.
    3. The client SHOULD support usernames of any length greater than zero.
  2. Passwords
    1. The client MUST NOT assume each user has a unique password. Like the real world, users may happen to choose the same password.
    2. The client MAY assume each user’s password generally is a good source of entropy. However, the attackers possess a precomputed lookup table containing hashes of common passwords downloaded from the internet.
    3. The client SHOULD support passwords length greater than or equal to zero.

3.2 User Sessions

  1. The client application MUST allow many different users to use the application at the same time. For example, Bob and Alice can each run the client application on their own devices at the same time.

  2. The client MUST support a single user having multiple active sessions at the same time. All file changes MUST be reflected in all current user sessions immediately (i.e. without terminating the current session and re-authenticating).

    For example:

    • Bob runs the client application on his laptop and calls InitUser() to create session bobLaptop.
    • Bob wants to run the client application on his tablet, so he calls GetUser on his tablet to get bobTablet.
    • Using bobLaptop, Bob stores a file file1.txt. Session bobTablet must be able to download file1.txt.
    • Using bobTablet, Bob appends to file1.txt. Session bobLaptop must be able to download the updated version.
    • Using bobLaptop, Bob accepts an invitation to access a file and calls the file file2.txt in his personal namespace. Bob must be able to load the corresponding file2.txt using bobTablet.
  3. The client DOES NOT need to support concurrency. Globally, across all users and user-sessions, all operations in the client application will be done serially.

3.3 Cryptography and Keys

  1. Each public key SHOULD be used for a single purpose, which means that each user is likely to have more than one public key.
  2. A single user MAY have multiple entries in Keystore. However, the number of keys in Keystore per user MUST be a small constant; it MUST NOT depend on the number of files stored or length of any file, how many users a file has been shared with, or the number of users already in the system.
  3. The following SHOULD be avoided because they are dangerous design patterns that often lead to subtle vulnerabilities.
    1. Reusing the same key for multiple purposes.
    2. Authenticate-then-encrypt.
    3. Decrypt-then-verify.

3.4 No Persistent Local State

  1. The client MUST NOT save any data to the local file system. If the client is restarted, it must be able to pick up where it left off given only a username and password. Any data requiring persistent storage MUST be stored in either Keystore or Datastore.

3.5 Files

Any breach of IND-CPA security constitutes loss of confidentiality.

  1. The client MUST ensure confidentiality and integrity of file contents and file sharing invitations.
  2. The client MUST ensure the integrity of filenames.
  3. The client MUST prevent adversaries from learning filenames and the length of filenames. The client MAY use and store filenames in a deterministic manner.
  4. The client MUST prevent the revoked user adversary from learning anything about future writes or appends to the file after their access has been revoked.
  5. The client MAY leak any information except filenames, lengths of filenames, file contents, and file sharing invitations. For example, the client design MAY leak the size of file contents or the number of files associated with a user.
  6. Filenames MAY be any length, including zero (empty string).
  7. The client MUST NOT assume that filenames are globally unique. For example, user bob can have a file named foo.txt and user alice can have a file named foo.txt. The client MUST keep each user’s file namespace independent from one another.

3.6 Sharing and Revocation

images/sharing_tree.png

  1. The client MUST enforce authorization for all files. The only users who are authorized to access a file using the client include: (a) the owner of the file; and (b) users who have accepted an invitation to access the file and that access has not been revoked.

  2. The client MUST allow any user who is authorized to access the file to take the following actions on the file:

    • Read file contents (LoadFile()).
    • Overwrite file contents (StoreFile()).
    • Append additional contents to the file (AppendToFile()).
    • Share the file with other users (CreateInvitation()).

    For example, all of the users listed in Figure 1 are authorized to take the listed actions on the file.

  3. Changes to the contents of a file MUST be accessible by all users who are authorized to access the file.

  4. The client MUST enforce that there is only a single copy of a file. Sharing the file MAY NOT create a copy of the file.

  5. The client MUST ensure the confidentiality and integrity of the secure file share invitations created by CreateInvitation().

  6. The client MAY assume that CreateInvitation() will never be called on recipients who are already authorized to access the file.

  7. The client MAY assume that CreateInvitation() will never be called in a situation where the sharing action will result in an ill-formed tree structure. In a well-formed tree structure, each non-root node has a single parent and there are no cycles. For example, in Figure 1, Nilufar’s attempts to share with Marco or Alice in steps 5 and 6 would be undefined behavior, since both users are already authorized to access the file, and the sharing actions would create an ill-formed tree structure.

  8. The client MUST enforce that the file owner is able to revoke access from users who they directly shared the file with.

    Any other revocation (i.e. owners revoking users who they did not directly share with, or revocations by non-owners) is undefined behavior and will not be tested.

    For example, in Figure 1, Alice is the only user who MUST be able to revoke access, and she MUST be able to revoke access from Bob and Nilufar. If any user other than Alice attempts to revoke access, or Alice attempts to revoke access from any user other than Bob orNilufar, this is undefined behavior and will not be tested.

  9. When the owner revokes a user’s access, the client MUST enforce that any other users with whom the revoked user previously shared the file also lose access.

    For example, in Figure 1, if Alice revokes access from Bob, then all of the following users MUST lose access: Bob, Olga, and Marco. As the file owner, Alice always maintains access. Nilufar maintains access because Bob did not grant Nilufar access to the file (Alice did).

  10. The client MUST prevent any revoked user from using the client API to take any action on the file from which their access was revoked. However, recall from Threat Model that a revoked user may become malicious and use the Datastore API directly.

  11. Re-sharing a file with a revoked user is undefined behavior and will not be tested.

3.7. I/O Efficiency

  1. The client MUST allow users to efficiently append new content to previously stored files.

    We measure efficiency in terms of the bandwidth used by the AppendToFile() operation rather than asymptotic runtime efficiency (the total size of the data uploaded and downloaded via calls to DatastoreGet() and DatastoreSet()).

    The bandwidth of the AppendToFile() operation MUST scale linearly with only the size of data being appended and the number of users the file is shared with, and nothing else. Logarithmic and constant scaling in other terms is fine. When thinking about efficiency in terms of bandwidth, it might help to think the Datastore as a remote storage, like cloud. The total size of data you upload and download from Datastore should not scale with any factors other than the size of data being appended and the number of users the file is shared with.

    For example, appending 100 B to a 10 TB file should not use 10 TB of bandwidth. The 1,000th and 10,000th append operations to the same file should not use significantly more bandwidth than the 1st append operation. This is not an exhaustive list of restrictions.

  2. AppendToFile() is the only function that has an explicit requirement for efficiency. However, the client MUST implement other functions such that they do not time out the autograder (e.g. they cannot be grossly inefficient).

    You can submit to Gradescope as often as you like to verify whether your tests finish within the allotted time (usually about ~10 minutes max).

3.8. Golang

  1. The client application code MUST NOT use global variables (except for basic constants).
  2. Your Go functions MUST return an error if malicious action prevents them from functioning properly. Do not panic or segfault; return an error.
  3. Your Go functions MUST return nil as the error if and only if an operation succeeds, and a value other than nil as the error if and only if an operation fails.