Hey, first, let me say, I'm not asking about things like md5(md5(..., there are already topics about it.

My question is this:

We allow our clients to store their passwords locally. Naturally, we don't want them stored in plan text, so we hmac them locally, before storing and/or sending. Now, this is fine, but if this is all we did, then the server would have the stored hmac, and since the client only needs to send the hmac, not the plain text password, an attacker could use the stored hashes from the server to access anyone's account (in the catastrophic scenario where someone would get such an access to the database, of course).

So, our idea was to encode the password on the client once via hmac, send it to the server, and there encode it a second time via hmac and match it against the stored, two times hmac'ed password. This would ensure that:

  • The client can store the password locally without having to store it as plain text
  • The client can send the password without having to worry (too much) about other network parties
  • The server can store the password without having to worry about someone stealing it from the server and using it to log in.

Naturally, all the other things (strong passwords, double salt, etc) apply as well, but aren't really relevant to the question.

The actual question is: does this sound like a solid security design ? Did we overlook any flaws with doing things this way ? Is there maybe a security pattern for something like this ?

Addendum: the reason we don't want to locally store the password in plain text on the client is because as sad as it is, many people still use the same password for multiple services, so getting the 'real' password would be a bigger security breach for the user than getting his hash stolen.

+6  A: 

Caveat: I'm not a security expert. I'll ping blowdart to see if he fancies joining in.

If the client is just storing the hash, and effectively transmitting something just based on the hash, then they're effectively storing it in plain text. The only benefit that the first hash is providing is that if they've used the same password on a different system, that other system won't be compromised if the hash is revealed.

To put it another way: if someone can get hold of the hash that's stored on the server, that's all they need to log into the system... just like plain text storage.

Jon Skeet
good point. all the hashing and double hashing confused me for a sec into thinking that it's quite secure! :)
I'm not sure how that would work. Let's say you got the hash that is stored on the server - how would you use that to log in ?
J. Stoever
@J. Stoever: Well, I was more meaning the hash stored on the client... but if they're the same thing, it doesn't matter. Basically at that point you've got everything the client would use to log in... it doesn't matter that you've not got the original plaintext password.
Jon Skeet

I'm not exactly sure what this buys you over storing the password locally in plaintext.

The purpose of local encryption is to prevent a hacker from being able to send the password to your server. However, if you are going to send the encrypted form over... well, you haven't bought anything.

Instead, the local machine should store the password in a two-way encrypted format. Meaning that it can be decrypted. Which you do prior to transmittal. The db can store a one-way encrypted format (even using a separate encryption mechanism). Prior to comparison, you encrypt what you received then check.

Chris Lively
A message digest function is not a method of encryption.

What is the initial hashing of the password intended to achieve? It will protect against discovery of the plain-text version of the password. It won't prevent the use of that hash value to calculate the doubly hashed value.

+3  A: 

No, this isn't safe. The hashed value is effectively the password. The fact the password was derived from something else that the user thinks of as the password doesn't matter. It's a secret value that authenticates a user, right? Sounds like a password to me.

I think it hinges on the statement, "Naturally, we don't want them stored in plan text, so we hmac them locally, before storing and/or sending." If the system is altered so that the hash password now has the same power the password once had, the same level of caution should be used with the hashed password.

+1 Although everyone shot down this protocol this is well put, i think the OP will understand it.
+3  A: 

As others have said, taking the client and your system in isolation this doesn't really buy you anything - the first hash simply becomes the password.

The value comes if (as is likely) the client uses that same password on other systems. In this case, should the client machine be compromised then at least your local copy of their hashed password doesn't allow the attacker access to other systems. Obviously the attacker of the client will now be able to access your server - they have, after all, got the password.

An attacker having access to the double-hashed value on the server won't buy them anything, since they can't reverse that to get the single hash (i.e., the "password"). Of course, if the attacker is in a position to read your security database then I suspect they have other attack vectors available :)

Also, as another poster said, make sure you are using a salt on both hashes. Without doing so, reversing the hashes may actually be quite simple if the passwords are not strong.

EDIT - actually, thinking about it, since you are using a hash as the password you don't really need to use a salt on the server. No way anyone is going to be able to create a rainbow table that's effective :) Still need one on the client though.

Steve Strong
This pretty much describes what I was thinking, short of not needing a salt on the server, but I suppose there isn't really a downside to using one anyways.Of course, there is no way to ensure the client can't be compromised if he stores the password, I wasn't looking for that.
J. Stoever
+11  A: 

I am running out the door, but the Skeet pinged and you don't mess with the Skeet.

What you're doing is replacing a password with another constant value. You gain nothing here, the only security you have is that the plain text password cannot be discovered on the client machine.

What you then appear to do is treating the HMAC (are you sure you mean HMAC? If so, where is the key coming from, and stored?) of the password as the password itself - you send it from the client to the server where it is used to authenticate. The second HMAC or hashing is meaningless - you're comparing against the value sent - it's a password by any other name. So, as an attacker, instead of stealing the password, I just need to steal the HMAC stored on the client machine. Nothing is gained at all here.

+1 you hit the nail on the head.
I'd much rather some random attacker know my hash than my actual password that I likely reuse in various places
Joe Philllips
I don't get this answer. The password stored at the client side is not plaintext, that's good. And access to the table of double-hashed passwords at the server does not enable an attacker to log in, that's also good.Granted, access to the hash stored at the client still allows login, and access to the server table means big trouble, but I still believe overall security is improved by the proposed idea?
How? All you're doing is replacing a plain text password with a hashed version of it. The hashed version is now the password, you've simply replaced a text password with a binary one. This binary is still stored in clear, and can be discovered and used. The only benefit is hiding the original password, which is only a benefit if the user uses it elsewhere.
+1  A: 

blowdart hit the nail on the head - you're just changing the secet to steal, not securing anything. What you're trying to replicate is an old authentication protocol that I can't for the life of me remember the name of. Here's how it works:

Upon initialization, the server gets your password, iteratively hashed n times, represented by Fn(pass). The client has the password, and the number n.

You go to authenticate, and send the server Fn-1(pass) - that is, the password hashed n-1 times. The server hashes it one more time, compares it to Fn(pass) and if they match you get access. The server then replaces Fn(pass) with Fn-1(pass) and you decrement n.

The next time you go to authenticate you send Fn-2(pass) and the process repeats.

Let's examine the security:

  • MITM: no resistence built into the protocol, you'd have to layer it inside SSL
  • Replay attacks: they don't work, because the server has decremented the hash iterations.
  • Eavesdropping: The next authentication will be done using Fn-1(pass). You have Fn(pass). Going from Fn(pass) to Fn-1(pass) is, by definition of the hash function, infeasible
  • Owning the server: You don't know the client's password, nor can you authenticate as them, because again you would need Fn-1(pass) when you only have Fn
  • Owning the client: Since you store Fn-1(pass) (so they don't have to enter pass) - then owning the client would let the attacker login. If you only store n and not the password this would be prevented, but you clearly want to save the password.

That's what you're trying to accomplish. However, there's a reason this protocol isn't in use - it's a giant bitch to syncronize. If the client and server get out of sync due to a half-completed step, you're locked out. Any resilience you built in to avoid that would likely reduce the security to replay or eavesdropping.

Tom Ritter
This is a one-time password scheme, examples of which include RSA SecurID and S/KEY. See and