Securing content and login with "same" password I'm writing a client application that wants to store some secret information with a storage service. The client has to authenticate the user with the service and the service should not be able to decode the information that it stores for the user. Authentication against the service has to be based on username - password combination (I also can't use local storage to store encryption keys on the client).

I want to minimize the information the user has to memorize (willing to sacrifice some security but not too much for this). Ideally just username plus 1 password. Is there a well understood cryptographic scheme that allows me to do that?

If not how well would the following work (from a security perspective):


Client app asks user for username (U) and password (P) .
Using cryptographic hash H(), the client registers the user with the user name U and password H(P). 
Client then encrypts the secret that is to be stored using some password based encryption (e.g. PBKDF2) using P.
Client then authenticates with the service using U and H(P) and uploads the secret information encrypted with P.


The thinking being that the server will only ever see H(P) and thus not be able to decrypt the secret (which requires knowledge of P) and also H(P) being a reasonable password for the service.
If you want to keep the crypto simple and mostly on the server side (which may be a good choice e.g. if you're developing a web service), you could use the following scheme:


To log in, the client sends the password $P$ to the server in clear, preferably over a secure channel (e.g. HTTPS).
The server derives a "master key" $K_0$ from $P$ using a key-stretching KDF (e.g. PBKDF2 or scrypt) and a salt $S$ stored in the database.  The length of $K_0$ should ideally match the natural output length of the KDF (e.g. 256 bits for scrypt or PBKDF2-HMAC-SHA256), and should be at least 128 bits.
The server uses a fast KDF (such as HKDF; note that extraction part of HKDF can be safely skipped, since $K_0$ is already a PRK suitable for direct expansion) to derive a verification key (i.e. a "password hash") $V$ of, say, 128 bits, which is compared against the corresponding value in the database to tell if the password is correct.  If it is, the server can use the same KDF to also derive additional key material, such as any number of file encryption keys $K_i$, from $K_0$.  After all necessary keys are derived, $K_0$ can and should be discarded.


Where desired and practical, the computationally intensive part of deriving $K_0$ from $P$ may equally well be performed on the client side.  However, $K_0$ should still be transmitted to the server over a secure channel, since under such a protocol it is still effectively a "password-equivalent authenticator".

Under this scheme, the server only stores $S$ and $V$ (and, of course, the encrypted files and any associated material such as IVs), which are not sufficient to recover $K_0$ or any of the file encryption keys.  A brute force attack on $P$ should be impractical due to the slow KDF used to derive $K_0$ from it; a similar attack on $K_0$ itself is infeasible due to the size of the keyspace.

The major and obvious weakness of this scheme, of course, is that a malicious or compromised server can still obtain $K_0$, and thus also any file encryption keys, when the user logs in.  Thus, while the user is safe from server compromises as long as they don't actively use the service, they do need to trust that the server is not currently compromised at the moment when they log in.



As long as the actual file encryption is done on the server, the weakness described above is unavoidable.  If this is not required, the obvious alternative is to perform the file encryption entirely on the client side (for which essentially the same key derivation process as described above may be used, just all done on the client) and in full control of the client (i.e. no running server-supplied crypto code on the client), and simply treating the server as a dumb file storage device.  The user can then be securely authenticated to the server using an augmented PAKE protocol such as SRP, possibly (but not necessarily) using the same password as for deriving the encryption keys.

Edit: ps. Even if the server can't be made to support SRP or some other augmented PAKE protocol (e.g. if the server runs some pre-existing software that you can't modify), a custom client could still securely store encrypted files on it by deriving both the file encryption keys and the server "password" (e.g. a 128-bit key, ASCII85 encoded for interoperability) from the user's actual password using a KDF as described above.  No matter how insecure the server may be, a compromise of the derived password will, at worst, allow an attacker to log into the server as the user, but it won't compromise the user's actual password or file encryption keys.

One difficulty here is that, without help from the server, there may not be any convenient place to store a salt for PBKDF2 / scrypt.  One way to work around that issue could be to derive the salt e.g. from the username and the server name; this is not ideal, but it's good enough for most purposes, especially if you also use a random per-file salt (stored as part of the encrypted file) when deriving each file encryption key from the master key.

In fact, even if you do store the salt on the server, it may still be a good idea to append the username and server name to it, since it can protect against some theoretical attacks (where a compromised server lies about the salt to find out if two users have the same password) as well as, more practically, against poorly implemented salt generation.