18
votes

What is a good, simple encryption scheme for protecting passwords in a database? I don't necessarily need anything that's hyper-secure nor do I need anything that's lightning fast, but those things would be nice. Primarily, I just want something that's easy to implement without being terribly slow or insecure.

14

14 Answers

15
votes

As mk says, SHA1 or MD5 are the standard ones, along with SHA2.


Update: As processors have gotten faster over the years, hashes have gotten more brute-forceable. It's now recommended you use bcrypt.


What you want is more generally called a cryptographic hash function. Cryptographic hashes are designed to be one-way (given the resulting hash, you shouldn't be able to derive the original input). Also, the likelihood of two arbitrary strings having the same hash (known as a hash collision) should be low (ideally 1/number of hash values).

Unfortunately, just because your passwords are hashed doesn't free you from having to try really hard to keep the hashed versions safe. Far too many people will use weak passwords that would be vulnerable to an off-line brute-force attack.

Edit - several people have also already pointed out the importance of using a salt. A salt is a constant value that you mix in with the input before using the hash function. Having a unique salt prevents off-line attackers from using pre-computed tables of common passwords (rainbow tables) to brute-force your passwords even faster.

10
votes

MD5 or SHA1 + salt.

10
votes

If you use MD5 or SHA1 use a salt to avoid rainbow table hacks.

In C# this is easy:

MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
string addSalt = string.Concat( "ummm salty ", password );
byte[] hash = hasher.ComputeHash( Encoding.Unicode.GetBytes( addSalt ) );
5
votes

Jeff's You're probably storing passwords incorrectly article is excellent reading on this topic.

4
votes

That was a problem of mine couple of weeks ago. We were deploying a large MIS project to 975 different geographical locations where our own user credential store will be used as an authenticator for different set of already implemented and in-use applications. We already provided both REST and SOAP based authentication service but customer insisted to be able to reach the user credential store from other applications with just a a DB connection to read-only view of related table or view. Sigh... (this highly coupled bad design decision is a subject of another question).

That forced us to sit and convert our salted and iteratively hashed password storage scheme to a specification and provide some different language implementations for easy integration.

We called it Fairly Secure Hashed Passwords or FSHP in short. Implemented it in Python, Ruby, PHP5 and released it to Public Domain. Available to be consumed, forked, flamed or spit on GitHub at http://github.com/bdd/fshp

FSHP is a salted, iteratively hashed password hashing implementation.

Design principle is similar with PBKDF1 specification in RFC 2898 (a.k.a: PKCS #5: Password-Based Cryptography Specification Version 2.0.) FSHP allows choosing the salt length, number of iterations and the underlying cryptographic hash function among SHA-1 and SHA-2 (256, 384, 512). Self defining meta prefix at the beginning of every output makes it portable while letting the consumer to choose its own password storage security baseline.

SECURITY:

Default FSHP1 uses 8 byte salts, with 4096 iterations of SHA-256 hashing. - 8 byte salt renders rainbow table attacks impractical by multiplying the required space with 2^64. - 4096 iterations causes brute force attacks to be fairly expensive. - There are no known attacks against SHA-256 to find collisions with a computational effort of fewer than 2^128 operations at the time of this release.

IMPLEMENTATIONS:

  • Python: Tested with 2.3.5 (w/ hashlib), 2.5.1, 2.6.1
  • Ruby : Tested with 1.8.6
  • PHP5 : Tested with 5.2.6

Everyone is more than welcome to create missing language implementations or polish the current ones.

BASIC OPERATION (with Python):

>>> fsh = fshp.crypt('OrpheanBeholderScryDoubt')
>>> print fsh
{FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhzGLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g==
>>> fshp.validate('OrpheanBeholderScryDoubt', fsh)
True

CUSTOMIZING THE CRYPT:

Let's weaken our password hashing scheme. - Decrease the salt length from default 8 to 2. - Decrease the iteration round from default 4096 to 10. - Select FSHP0 with SHA-1 as the underlying hash algorithm.

>>> fsh = fshp.crypt('ExecuteOrder66', saltlen=2, rounds=10, variant=0)
>>> print fsh
{FSHP0|2|10}Nge7yRT/vueEGVFPIxcDjiaHQGFQaQ==
3
votes

Use the SHA one way hashing algorithm along with a unique salt. It is the main algorithm I use for storing my passwords in the database.

0
votes

If you're using SQL Server, there's the HashBytes function:

http://msdn.microsoft.com/en-us/library/ms174415.aspx

0
votes

I second the vote for MD5 or SHA with a salt. Any of the major web development languages have functions built-in for computing the hash (in PHP, for example, the mcrypt package contains the necessary functions).

0
votes

You need to be using an uni-directional hash algorithm like SHA-1 suggested above with a salt. I would suggest this site for more information. It includes some sample code / implementation. http://www.obviex.com/samples/hash.aspx

0
votes

The key to better security, I think, is to use dynamic salts. This means that you generate a random string for each new user and use that string to salt the hash. Of course, you need to store this salt in the database to be able to verify the password later (I don't encrypt it in any way).

0
votes

For a non-reversible encryption I would most definitely go with SHA256 or SHA1. MD5 has quite a lot of collisions now and a lot of effort has been put into breaking it, so not a good one to use.

0
votes

If you want to future-proof your solution, I'd recommend SHA256 or SHA512. Cryptographic geekworld is getting the jitters about MD5 and, to a slightly lesser extent, SHA1.

Or, if you can, wait for SHA-3

0
votes

I've noticed a lot of confusion about how to do password hashing properly, especially on stackoverflow. So I've written a page that should clear everything up. There's a bit more to it than using a simple hash.

More info: How to do password hashing properly