I'm creating a cloud storage service and need to have the ability to provide reliable security for clients. In my previous question, I used a different schematic and said I would post a new question.

I'm still trying to achieve security against the NSA and the possibility of legal issues. I would like to have my users encrypt their files before sending them to my servers. I will use AES-256 and the key will be created by hashing the user's password 1,048,576 (2^20) times to avoid brute force attempts.

The issue is that anyone can upload files, delete files, or modify them this way. I need to be able to verify the password, but at the same time, not expose it to the server. I was wondering if the password could be use to sign the information sent to the server, to not only verify the identity of the user, but also prevent tampering of the contents during transportation. What is the best way to do this without exposing the password or its hash?

  • 1
    If you can afford it, upgrade your hash to scrypt Nov 11, 2013 at 15:50
  • 1
    Asymmetric encryption is required to be able to sign and verify signing without exposing the password. You can have a user's asymmetric private key be derived from their symmetric (AES) key, and have the public component stored on your cloud. Note that implementing things like this yourself rather than using existing (debugged, vetted) libraries is asking for problems.
    – mah
    Nov 11, 2013 at 17:22

4 Answers 4


Hashing multiple times to slow down brute-forcing is a bad idea, because each time you hash you reduce entrophy and thus makes incidental collisions more likely. When you intentionally want to slow down hash calculation, use an algorithm with an adjustable complexity, like bcrypt.

When you want to make sure that a message is 1. from the user you expect it to come from and 2. wasn't tampered with, you need to use a cryptographic signature. A cryptographic signature can be created by creating a hash of the message and then encrypting that hash with the private key of the sender. The receiver can then calculate the hash of the message it receives, decrypt the alleged hash with the public key of the sender, and verify that the hashes match. The security comes from the fact that it is impossible to forge a matching hash without knowing the private key of the sender.

But how do you obtain the public key of the sender? Either you received it beforehand on a more trustworthy channel. Or you get a trusted 3rd party to cryptographically sign the senders public key with their private key. Some trustworthy "certificate authority" you can rely on that they verified the identity of your communication partner properly. And congratulation, you just reinvented TLS.

"But what about the password"? Well, at some point in the past, your server must have received the password. Or the hash of the password. Or the hash of the hash of the password. The password is just like the public key of the user. How do you know this first time your received this wasn't tampered with? You can't. No cryptographic system works without having verified the identity of one of the communication partners at some point in the past, either directly or via a certificate chain.

  • 1
    Loss of entropy due to repeated hashing is negligible if you use a good hash like SHA-2. Even with a 128 bit hash like MD5 it's no big deal. Dec 11, 2013 at 23:00
  • @CodesInChaos But it doesn't make the hash any better, so it is "not very harmful" at best.
    – Philipp
    Dec 11, 2013 at 23:10
  • Iterating a SHA-2 has pretty much the same security properties as PBKDF2-HMAC-SHA-2. The latter is much more complicated but these complications don't improve security. (And the implementation difficulties often reduce security if the implementer doesn't carefully optimize it. Consider the 2x slowdown of the .net implementation, or the ridiculously bad django implementation) IMO SHA2^n(SHA2(salt)+password) is just as good as PBKDF2 and much simpler. Dec 11, 2013 at 23:14

If you don't want the server to have the password nor any form of hash, you will need some alternative form of credentials.

You could, for example, create your own CA (doesn't need to be trusted by anyone else), and issue the users client authentication certificates.

However, if you are willing to give the server the hash of the password, you can do the following:

  • Let the user choose a strong password
  • Let the user derive two random 256-bit keys from this password using PBKDF2
  • The first key is now a ECDSA signature private key. The user calculates the public key and provides to you during registration. This key now represents the user. Any API request has to be signed with this key.
  • The second key is used to symmetrically encrypt the files.

Now, this would mean that the user can never change his password. For this reason, what usually happens is the following:

  • Let the user choose a strong password
  • Let the user derive two keys, pwkeyA and pwkeyB.
  • The user generates something he can use to authenticate himself to you properly (e.g. keypair or a symmetric key of which you receive a copy). The symmetric key or the private key is authKey.
  • The user generates a file encryption key encKey.
  • The user encrypts encKey and authKey under pwkeyA, resulting in an encrypted blob. He now gives this encrypted blob to you. Note: You could now attempt to bruteforce the user's password by deriving pwkeyA and trying to decrypt the blob.
  • If the user wants to access his data, he requests the blob, decrypts it using pwkeyA, and authenticates to you using authKey. He then downloads a file and decrypts it using encKey.
  • If the user wants to change his password, he downloads the blob, decrypts it using pwkeyA (derived from the old password), encrypts it using pwkeyA (derived from the new password), and stores it on your server.
  • Now, you don't want anyone to be able to wipe the key blob of your user, do you? You probably also don't want anyone to allow downloading that blob and running offline bruteforce on it. That's where pwkeyB comes in. This is used as a "password" to log into the "key storage" and download/upload the key blob. Note that pwkeyB is basically a hash of the password. You could further improve security by using pwkeyB as a private ECDSA key and doing the thing in the first example.

For integrity-checking of the files, the user may want to derive more keys from the encryption key, and use one for AES-CBC, the other one for HMAC. Or use an authenticating cipher mode. This is irrelevant to the key management problem though.


NOTE: I'm an arm-chair crypto guy...(aka not a mathematician) so take that into consideration. However, I've pen-tested and "broken" a fair share of poorly implemented crypto.

Step 1, adequately secure the communications channel.

Ensure your TLS/SSL certificates implement perfect forward secrecy. Good news is that it isn't difficult to implement, but it has to be done on the server. This prevents adversaries from being able to capture traffic and later decrypt it after they've obtained your private TLS key (either legally or illegally).

In Moxie's (he wrote SSLstrip) recent critique of Lavabit, he explains some security issues related to email providers, which may be relevant in your situation.

A typical (unencrypted) email provider has three main adversaries:

  1. The operator, who has access to the server.
  2. An attacker who can get access to the server.
  3. An attacker who can intercept the communication to the server.

I'm glad to see you are thoroughly hashing the password, but commenting on it would put me out of my depth. I hear lots of people smarter at crypto than me recommend PBKDF2.

This is only a partial answer, but securing the communications channel with perfect forward secrecy is job 1.

  • The weakpoint of TLS is that you need to trust the certificate authorities to not sign a certificate for someone who wants to impersonate you.
    – Philipp
    Nov 11, 2013 at 15:45
  • ...which already happened, by the way: en.wikipedia.org/wiki/…
    – Philipp
    Nov 11, 2013 at 15:52

Moved to another question:

Any issues with this security design for cloud storage? Server doesn't even need to know password to log someone in

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .