5

I've been tasked with finding a better way to store passwords and came up with this Algorithm. My understanding of Crypto is not strong enough but can someone check this please?

Inputs: Username Passcode

Algorithm:

Pass Username through uuid (RFC 4122) to get hashed Username (this is mostly to generate a fixed length string so that the DB can index it tidily)

Select uuid from database to get ID.

Salt = md5(Hashed Username + db ID + Password)

Discard input variables.

sha512(password, salt, rounds)

Where rounds = 2 ^ ((days between now - 1st Jan 2008)) / 365) * factor (50000 perhaps).

Discard the hints in the resulting string about salt and rounds (they can be regenerated).

Store the hashed payload.

Output:

A string to be tested against the stored string, changes every login due to constantly increasing rounds.

NlightNFotis
  • 1,130
  • 1
  • 10
  • 18
user13037
  • 59
  • 3

8 Answers8

16

Don't do this. Please don't. It will make those who come after you hate you. And may or may not be secure at all.

Just use an existing library for hashing passwords. Preferably one that uses the crypt(3) library underneath (depending on the language, I'd suggest one, but you didn't indicate a target language).

Your method of salt generation isn't horrible, but it isn't great either.

Just stick to existing algorithms. They exist and are recommended for a reason... Don't try to invent your own just to be clever. It may work, but usually it won't...

ircmaxell
  • 1,416
  • 12
  • 16
8

User ID hashing?

Pass Username through uuid (RFC 4122) to get hashed Username (this is mostly to generate a fixed length string so that the DB can index it tidily)

Select uuid from database to get ID.

This is pointless -- databases can index variable-length strings just fine. In fact, they'll do it better than a UUID since most usernames are less than 32 characters long, so you're just:

  • Making your program more complicated
  • Making your indexes larger

Salt

Salt = md5(Hashed Username + db ID + Password)

Why? Salt is just supposed to be a unique value, so this massive overkill and arguable less useful than a completely random salt. Just grab some random data from somewhere (/dev/random or whatever Windows has) and store it in the database. You're looking up the password anyway, so grabbing the salt too won't slow you down at all.

The fact that you're salting these values suggests that you don't really understand what's happening.

  • If this value was stored anywhere, your password hashing scheme is broken (because md5(user+id+password) is much easier to bruteforce than PBKDF2-sha512(password, salt, rounds). You probably know better than to store it, but someone else may come along later and "optimize" it..
  • If it's not stored anywhere, there's no point in hashing it. Just use user+id+password as the salt directly.

Dynamic rounds

Where rounds = 2 ^ ((days between now - 1st Jan 2008)) / 365) * factor (50000 perhaps).

So what happens when you look it up tomorrow? Suddenly the number of rounds is different and your passwords don't match. You'll need to store this somewhere, and the database is the easiest place. Also, if your hardware can support a higher number of rounds, why not just start with the highest number you can come up with?

If you want to get a new hash every time someone logs in, just generate a new salt every time.

Conclusion

You can get everything you want, with none of the security vulnerabilities by just doing things the standard way (bcrypt or PBKDF2, with random salts, and rounds set the highest value you can handle).

Brendan Long
  • 2,898
  • 1
  • 19
  • 27
6

There's one very significant flaw (assuming you meant the standard cryptogrpahic salt which is necessarily stored in the database):

salt = md5(Hashed Username ++ db_ID ++ Password)

With normal salts they are stored in the database and likely the username is stored in a separate column, so if an malicious admin or SQL injector ever gets their hands on the DB, they can use just the stored MD5 salts to brute force the passwords. Since MD5 is a very weak salt, unless the password is very high entropy, a GPU can crack it by trying a several billion passwords per second [1].

However, you may have meant your database only stores username and multi_round_hash_sha512_hash; specifically not storing the username derived 'salt' like the following example (where ++ is concatenation):

db_id = uuid(username);
username_derived_salt = md5(username ++ db_id ++ password);
# this salt not stored in DB
multi_round_hash = password;
for(i=0; i < rounds; i++) {
    multi_round_hash = sha512(multi_round_hash ++ username_derived_salt);
}

In that case this is not a flaw, though it is basically equivalent to using a username itself as a salt with a little obscurity on top of it.

Also, using a dynamic number of rounds that increments over time seems unnecessarily complicated and I don't see the benefit versus having a fixed number (say 100 000 rounds; that you may choose to boost at some point). I foresee many implementation issues (timestamps being misaligned between users so number of rounds being different; having a cron job add extra round to stored hashes at each day -- possible issues with users trying to login around midnight; daylight savings time/timezone issues). At the very least store the number of rounds with the hashed password and test very thoroughly.

Using something like bcrypt/PBKDF seems much more straightforward.

dr jimbob
  • 38,936
  • 8
  • 92
  • 162
3

It looks good, appart from your salt not being random. You are really making it (unnecessarily ) complicated. You could just use Bcrypt which makes your life a lot easier IMHO.

Lucas Kauffman
  • 54,229
  • 17
  • 113
  • 196
3

In addition to the other good answers here, since you are using SHAxxx you may find it interesting that there is hardware that can quickly create SHA256 hashes as extraordinary speeds. Although this isn't currently a security vulnerability, bcrypt is made so it resists FPGA based attacks.

Also your code seems to violate at least one best practice of cryptography: Don't invent your own crypto code.

The preferred solution is to use bcrypt or PBKDF2

makerofthings7
  • 50,488
  • 54
  • 253
  • 542
1

It is always suggested that a standard, proven mechanism is used when storing passwords. While your algorithm may be secure enough, as the other answers have suggested, it may be difficult for others in the future to follow. Hence, common methods such as using PBKDF2 to create hashes of passwords have been used. http://crackstation.net/hashing-security.htm#javasourcecode this link is an excellent resource which provides the code/technique to store password hashes and is available for most common languages.

sudhacker
  • 4,300
  • 5
  • 23
  • 35
0

MD5 is cryptographic hashing algorithm designed for speed, and therefore is bad for storing passwords, even with a salt. Use something slow like HMAC with a complex salt that is acceptably slower - yes it means that login operations will be imperceptibly slower but it also means that anyone who gets hold of your hashed password database has to spend 10x as much time cracking passwords thus 10x fewer passwords will be exposed in the event of a catastrophic hack.

-1

also if youre going to salt your hashes I think you should use sha1 instead of md5 hashing because md5 has been found to be insecure

Ahmad
  • 1