views:

1296

answers:

14

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.

+9  A: 

MD5 or SHA1 + salt.

mk
+2  A: 

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.

Dale Ragan
+8  A: 

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 ) );
Keith
A: 

Don't use md5 - it's easily crackable as it's developed for speed rather security.

In PHP I tend to use sha1 with a salt (sometimes two) for passwords (they're not immesnely important. This is sufficient for me.

Here's a technique I sometimes use - I call it the sandwich technique :P

$password = 'sample';
// Split into half
$password = str_split($password, strlen($password) / 2);

// Random characters to make it seem unencrypted if it is encrypted
$salts = array(
    1 => 'fd2rc',
    2 => 'dsd3f',
    3 => '34fcx'
);

// Sandwich your password
$password = $salts[1] . implode($salts[2], $password) . $salts[3];

You could also use bcrypt if you install the mcrypt library which is more secure.

Ross
I agree with you about MD5 being not secure, and salts are necessary as well -- but the "sandwich technique" seems really unscientific and therefore insecure. Use salts in a good way instead.
Christian Davén
A: 

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

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

Joel Coehoorn
+4  A: 

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

Greg Hewgill
A: 

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).

Justin Bennett
Why do people randomly go around and downvote perfectly legitimate answers?
Justin Bennett
A: 

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

Thomas
+12  A: 

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

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.

Neall
For the OP: When using a one-way hash such as MD5 or SHA1/2, you can't "decrypt" it. That is, you won't be able to recover the original plaintext password from the hash string. To test the password when the user logs in, apply the same hash to the inputted password and compare the two hashes.
Barry Brown
Well written, easy to understand!
toto
+2  A: 

Easy: BCrypt.

graham.reeds
Easy - and more importantly correct, standard and well-tested.
caf
the only correct advice
Jacco
A: 

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).

Christian Davén
+2  A: 

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==
Berk D. Demir
A: 

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.

Mark Davidson
A: 

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

Brent.Longborough