1

I'm not sure the title is accurate, please feel free to rename the question if appropriate.

I'm thinking about a service that stores sensitive data on a remote server. For maximum privacy, the data would be encrypted on the client (using AES) and the encryption key not stored in any place, so that should the server be compromised, sensitive data would still be relatively safe.

Now the problem is, I need a second password to access the service, but this second password must be stored somewhere on the server.

This would be what happens when a user registers:

  • user picks a username/password (Password A) and an encryption key (Password B).
  • hash(Password A) is stored on the server
  • Password B isn't stored anywhere.

then:

  • user enters Password A => Password A is transmitted to the server
  • server checks hash(Password A) against the user db, grants access
  • client downloads preferences and encrypted data
  • User enters Password B -> encrypted data is decrypted (locally).

This looks good to me, but the drawback is that the user needs two distinct passwords. This is impractical and also carries the risk that users pick the same string for both, strongly reducing the model's effectiveness.

What I would like is to use two independent passwords but only ask the user a single one.

First attempt

The first idea I had is to ask the user a password, then split it in two and use the first part as service credentials (Password A) while the second part would be the encryption key (Password B).

This has the drawback of reducing the strength of the passwords: if the user-provided string is already weak/short, Password A and Password B would be even weaker.

Second attempt

Another option: use the user-provided password as encryption key (Password B) and use a hash (SHA-256) of that password as service credentials.

Registration:

  • user picks a single password PASS
  • hash(PASS) is transmitted to the server
  • server stores hash(hash(PASS)) with username in the user db

Then:

  • user enters PASS
  • service sends Password A = hash(PASS) to the server
  • server checks hash(Password A) against the user db, grants access
  • client downloads preferences and encrypted data
  • client decrypts encrypted data with Password B = PASS.

This means that

  1. a hash of the encryption password travels over the network 2) a
  2. a hash(hash(encryption key)) is now stored on the server, i.e. alongside the encrypted data

Does this significantly reduces the security of the system? I.e. when an attacker gains access to the server, is it easier to decrypt the sensitive data when knowing hash(hash(encryption key))?

Is there another (better) way to get two independent passwords starting from a single string?

Jayy
  • 2,368
  • 4
  • 24
  • 35
Francesco De Vittori
  • 9,100
  • 6
  • 33
  • 43

5 Answers5

2

I would go a different approach. Using openid to authenticate to your system. This way you do not have to transmit a password to your server at all.

On your first approach, you should only transmit the hash.

Tim
  • 2,051
  • 17
  • 36
1

If I remember correctly, LastPass uses this system:

  1. User enters email address and password
  2. Password is hashed and the hash used as key to encrypt the user's sensitive data
  3. Password hash + email is hashed into a second password which is used to log into the server and upload the encrypted data blob

I may have it backwards which hash is used for which, but it sounds like you want something very similar. The whole thing was explained in detail in Security Now #256, if you're interested.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • This is the closest to what I need. I don't want to use Open ID or any other external authentication because first the application is going to run on wildly different environments, second it must work offline, third it's not a web app (making open ID very impractical). – Francesco De Vittori Mar 01 '12 at 08:12
1

As suggested by @Tim in his answer - do not create a new user authentification scheme (your own user-id & password combination).

Based on what you are building this for, you basically have 2 options:

  • If this in an corporate internal application just integrate to Active Directory or whatever internal user database and authentication backend you have
  • If this is public, use OpenID (if you need just authentication) or OAuth if you also need authorization.

Please note that your application does not have to be web based in order to use them. (You do need internet access, though). See this question for details

For the encryption keys, use some sort of Key Derivation Function (also known as PRF+) for the key derivation - preferably with other components as well. Feed the PRF/KDF for example the following (concatenated):

  • User's unique identifier from the authenticator (OpenID, AD, whatever)
  • a system-wide application identifier string (e.g Francescos secureapp keypad)
  • per user random data stored with the user information (e.g. 16 bytes from the system random source)
  • user's encryption password - this is the single password you have to care about.

This is somewhat similar to AUTH payload calculation in the IKEv2 protocol

This way the potential attacker would need to access bits of information from various locations in order to be able to decrypt user's sensitive data.

Also, don't store the user's encryption password on the server side. The client should always ask it (or cache it for certain amount of time) from the user and send it (in plain or hashed) over an encrypted channel to the server whenever requesting something that needs [en|de]cryption.

Furthermore, if you want to enforce some sort of a password policy on the encryption passwords, see this comic and this answer for reference how it should be done.

Community
  • 1
  • 1
Kimvais
  • 38,306
  • 16
  • 108
  • 142
1

The advice to use a secure password scheme is correct. What you might want to do is to make a small change before passing the user's text to the password scheme. If the user enters "password" then pass "passwordLOCAL" to the local password scheme and "passwordREMOTE" to the remote password scheme.

That allows the user to enter a single password yet still have two different local and remote passwords. Don't actually use "LOCAL" and "REMOTE" of course, far too insecure. Use two different random strings, much like two different salts.

rossum
  • 15,344
  • 1
  • 24
  • 38
0

You could generate and store an IV (or two, if needed) on the server, and send it to the client to HMAC. This produces the encryption keys that are needed.

Ivo
  • 5,378
  • 2
  • 18
  • 18