15

I've got an old application that has user passwords stored in the database with an MD5 hash. I'd like to replace this with something in the SHA-2 family.

I've thought of two possible ways to accomplish this, but both seem rather clunky.

1) Add a boolean "flag" field. The first time the user authenticates after this, replace the MD5 password hash with the SHA password hash, and set the flag. I can then check the flag to see whether the password hash has been converted.

2) Add a second password field to store the SHA hash. The first time the user authenticates after this, hash the password with SHA and store it in the new field (probably delete their MD5 hash at the same time). Then I can check whether the SHA field has a value; this essentially becomes my flag.

In either case, the MD5 authentication would have to remain in place for some time for any users who log in infrequently. And any users who are no longer active will never be switched to SHA.

Is there a better way to do this?

Bruce Alderman
  • 2,284
  • 2
  • 27
  • 38
  • 3
    Your two solutions look ok to me. – wtaniguchi Sep 04 '09 at 20:47
  • And I'm upping Ned's answer, he has a good point there. – wtaniguchi Sep 04 '09 at 20:49
  • 5
    As for users who are never switched - I'd consider after a certain percentage of people are switched over and enough time has passed to just get rid of the MD5 hashes. People who haven't logged on during that period of time will have to have their passwords reset when and if they ever log in again. Whether or not (and when) that's acceptable is a business decision. – Michael Burr Sep 04 '09 at 20:54
  • 2
    I'm wondering if you really need an extra flag: the length of the old hashes is shorter anyway. – mark Sep 04 '09 at 20:54
  • 2
    Stating the obvious: Don't forget to rehash the passwords AFTER validation :-) – Vinko Vrsalovic Sep 04 '09 at 20:55

7 Answers7

11

Essentially the same, but maybe more elegant than adding extra fields: In the default authentication framwork in Django, the password hashes are stored as strings constructed like this:

hashtype$salt$hash

Hashtype is either sha1 or md5, salt is a random string used to salt the raw password and at last comes the hash itself. Example value:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
Jørn Schou-Rode
  • 37,718
  • 15
  • 88
  • 122
  • The only issue with this is that it stores the salt in such a way that makes it obviously the salt, rather than using another unique or derived value for the user (such as a mutated version of the timestamp of their account creation, or bit-flipping their username, etc). It's arguable whether this makes any currently feasible difference in how long it would take to crack, I'm just paranoid. – defines Oct 30 '09 at 15:22
  • @Dustin: the extra strength here is the salt can be changed every time the user changes his password. – Joshua Jun 14 '10 at 17:10
  • But you're storing the salt. If I have your DB and all your hashes, I have your salts too. – defines Jun 14 '10 at 20:19
  • 1
    @Dustin: In this setup, the salt is merely there to render attacks using [rainbow tables](http://en.wikipedia.org/wiki/Rainbow_table) useless, as the salt will be different for each user. – Jørn Schou-Rode Jun 14 '10 at 21:19
  • Yes I understand the benefit, I was merely stating I personally prefer not to store the salt so that it is obviously the salt. As I said before knowing the salt doesn't necessarily make it any more feasible to crack the password, but I'm paranoid. I use a salt that's different for every user, but it's derived from another value unique to the user. Even if you have my whole DB you won't know where the salts are coming from unless you also have the application code. Probably not a practical increase in security because salting alone is enough (currently), but it IS more secure to hide the salt. – defines Jun 15 '10 at 17:25
  • Good security rests on the assumption that any potential attacker knows your methods. That's why we use "crytographically secure" hashed, not "cryptographically obscure" hashes. As Jørn points out, the only (quote "merely") added security of a hash is to defeat rainbow tables and such. They are a complement to cryptographically secure hash functions. – maxwellb Jun 25 '10 at 19:49
6

You can convert all your MD5 Strings to SHA1 by rehashing them in your DB if you create your future passwords by first MD5ing them. Checking the passwords requires MD5ing them first also, but i dont think thats a big hit.

php-code (login):

prev: $login = (md5($password) == $storedMd5PasswordHash);

after: $login = (sha1(md5($password)) == $storedSha1PasswordHash);

Works also with salting, got the initial idea from here.

Community
  • 1
  • 1
wolph
  • 71
  • 1
3

I think you've already got the best possibilities. I like #1 more than #2, since there's no use for the md5 once the sha is set.

There's no way to reverse the MD5, so you have to wait for the user to authenticate again to create a new hash.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
2

No - basically you'll have to keep the MD5 in place until all the users you care about have been converted. That's just the nature of hashing - you don't have enough information to perform the conversion again.

Another option in-keeping with the others would be to make the password field effectively self-describing, e.g.

MD5:(md5 hash)
SHA:(sha hash)

You could then easily detect which algorithm to use for comparison, and avoid having two fields. Again, you'd overwrite the MD5 with SHA as you went along.

You'd want to do an initial update to make all current passwords declare themselves as MD5.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    The size of the hash makes it self-describing: MD5 is always smaller. – Steven Sudit Sep 04 '09 at 20:48
  • 2
    Length shouldn't be used as the sole indicator. You might want to change what goes in the hash (e.g. nonce calculations, other seed data) while using the same hash algorithm to chop it all up. Having a separate identifier indicates to you which of *your* password hashing schemes is in use. – Rob Sep 04 '09 at 20:53
  • 1
    If your only two methods differ in length then you certainly can use length as an indicator. – Vinko Vrsalovic Sep 04 '09 at 20:54
  • 1
    Rob, I agree that having an extra byte or so up front as an indicator is a good idea. Conveniently, the legacy MD5 values will be shorter than even an MD5 with that extra byte. – Steven Sudit Sep 04 '09 at 20:58
0

Your second suggestion sounds the best to me. That way frequent users will have a more secure experience in the future.

The first effectively "quirks-mode"'s your codebase and only makes sure that new users have the better SHA experience.

Jeff Wilcox
  • 6,375
  • 1
  • 24
  • 31
  • To me it seems the two solutions are the same, only implemented slightly differently. In either way, your password is rehashed on your next login. – Jørn Schou-Rode Sep 04 '09 at 20:52
  • In either option, I would replace the passwords of existing users the next time they log in. It's just a question of how to let the app know which hash to use after that. – Bruce Alderman Sep 04 '09 at 20:54
-1

If the MD5's aren't salted you can always use a decryption site/rainbow tables such as: http://passcracking.com/index.php to get the passwords. Probably easier to just use the re-encode method though.

Meep3D
  • 3,803
  • 4
  • 36
  • 55
-4

Yes you should know the real password first before you convert it into sha-1..

If you want to find the real password from md5 encrypted string, you can try md5pass.com