0

I've created an algorithm I think I'm going to use for a cloud storage service I'm developing- if there are no issues or vulnerabilities with it. It's this along with TLS and forward secrecy implemented. Also when logging in on a new device you must confirm it through your email account.

To create account:

  1. Generate two random keys, Key A and Key B. Key A is used to prove the identity of who is signing on. Key B is used to encrypt your files with AES-256.

  2. Encrypt the two keys with AES-256 using a hash of the user's password. I'm going to post a separate question soon about intentionally creating a delay in the hashing function, to prevent brute force attacks.

  3. Send the encrypted keys to the server, along with an SHA-256 hash of Key A.

To login:

  1. Download the encrypted keys from the server.

  2. Decrypt the keys with the hashed password.

  3. Upload Key A to the server.

  4. The server hashes Key A and compares it against the stored hash. If the two are identical, notify the client that the password is correct (not that it was sent over).

  5. Delete the copy of Key A in memory from the server.

To make changes to files:

  1. Log in using the steps shown above. The server will reject any actions unless logged in, obviously.

  2. Encrypt all files with AES-256 using Key B (stored in memory on the client, never stored in plaintext on the server) before sending online. Decrypt all files offline accordingly.

To change the password:

  1. Log in using the steps above.

  2. Encrypt Key A and Key B (stored in memory after logging in) with the hash of the new password.

  3. Instruct the server to delete the encrypted keys and upload the new ones.

To reset password and keys (in case of breach):

  1. Log in. If you can not do so with the password and the steps above because your password was changed, use a recovery drive (optionally created when setting up a new account) with the keys stored on it.

  2. Download all files from the server.

  3. Decrypt the files with Key B.

  4. Generate two new random keys, then encrypt the new keys with the new password and upload them, along with a hash of the new Key A.

  5. The server caches the encrypted keys and hash, and sends a confirmation email to reset the account password and keys.

  6. Once the confirmation email is accepted, the client begins encrypting the files with the new Key B and uploading them to the server. Once all files are completely transferred, the server removes the old files.

  7. All keys are invalidated, signing out of the account on all other devices.

Please let me know if there are any problems with this algorithm or improvements I could make.

Phoenix Logan
  • 482
  • 2
  • 13

1 Answers1

2

The tricky point in all such password-based protocols is prevention of offline dictionary attacks. A dictionary attack is when the attacker tries potential passwords; it is offline if the attacker can do that at home without interacting with the genuine server or the target user. Offline dictionary attacks tend to work well, because users are human users, and thus, on average, their passwords suck big time. Slow and salted hashing (see this answer) can help to some extent, but will not ultimately fix the issue. Passwords are weak.

It is unavoidable that there is enough on the server to run an offline dictionary attack. Indeed, if the attacker gets a complete copy of the server contents, then he can emulate the server on his own machines. The running server must somehow device whether an incoming client, armed with only his password, is to be allowed destructive operations on files or not; therefore, the server must be able to distinguish between a correct and an incorrect password. An attacker emulating the server and the client can then "try passwords" and that's by definition an offline dictionary attack.

The problem, then, is to make sure that only the server has this power; that values allowing offline dictionary attacks are not needlessly distributed to the public at large. So, in your proposal, there are vulnerable areas. In particular:

  • The "key A and B encrypted with the password" may allow to run an offline dictionary attack. Since this blob is obtained from the server before actual login, then anybody can have it, including the attacker. The encryption format has to be quite special in order to prevent it being abused that way (a hand-waving description of it is that decryption with the wrong password must still appear to work). Usual encryption formats will be weak.

  • Similarly, there are stored files, encrypted with key B. An attacker with the "keys encrypted with the password" blob and an encrypted file can use that to test for potential passwords (try passwords until the file decryption yields something which "makes sense"). This implies that the encrypted files must not be shown to anybody except the rightfully authenticated user (you need user authentication for read access, but also for write access).


It would be more generic and less confusing to separate your two keys A and B: they really are distinct kinds of objects, and are used in different ways. What you really want is the following:

  1. A password-based authentication method, in which the server does not learn the user's password but can verify it nonetheless.
  2. A storage for files with password-based encryption. This storage will use a two-step encryption system: a symmetric key K is encrypted with the password, and all other files are encrypted with K (this speeds up password changes).

Note that the part about not learning the user's password really is: not learning that which is used to actually encrypt the files. The generic method would be the following: for a given user password P, compute f(P) with a proper password-hashing function f (say, bcrypt or PBKDF2). Extend the result with a Key Derivation Function into two keys U and V (PBKDF2 includes its own KDF; otherwise, a cheap KDF can be a simple invocation of a hash function like SHA-256 if the output size is large enough to be split into U and V). Server stores h(U) for some hash function h, and V is used to encrypt the symmetric key K.

With this system, the server learns U but this gives him no hint on V, by application of the virtues of the KDF (a KDF is, mostly, a hash function with a configurable output size). Moreover, U is still after the f() function, hence U allows for only a slow offline dictionary attack, something which the server could already have done.

This system requires that any user can obtain his salt prior to authentication. This is not a problem, since this salt is just a random value. Notice how this alternate protocol removes the need for a "special encryption system" which does not allow an offline dictionary attack.

For extra brownie points, use U as the password for TLS-SRP. This will ensure mutual authentication between client and server, based on the password, without needing any certificate at all.

Tom Leek
  • 170,038
  • 29
  • 342
  • 480
  • First, since the keys are completely random, wouldn't any attempt to brute force require testing the key server-side with the stored hash? The stored hash is not downloadable. The account could be locked out after a certain number of tries, and the user could be notified through email. Second, the files are inaccessible until Key A is provided correctly. It would be impossible to brute force Key B since there'd be nothing to test against. – Phoenix Logan Dec 27 '13 at 21:14
  • Depends on how the encryption is done. If you do it "normally" there will be a padding, which is sufficient (for the attacker) to test for correct decryption (at least to weed out 255/256th of potential passwords). Ditto if there is a MAC (as is customary). – Tom Leek Dec 27 '13 at 21:18