Hashing vs. Encryption: How Your Password Is Being Stored in Server

Let’s say you set up an account at VerySecureWebsite.com. You type in your email address and password and set up your account. A little while later you receive an email informing you that, ironically, the website has been hacked, and the usernames and passwords of every user, which were stored in plaintext, are now for sale on the dark web. While you start changing the password on all your accounts (you only use one, you monster), you wonder, “Isn’t that a bad idea? Shouldn’t my password be in some kind of secret code so hackers can’t just read it?

You’re correct. Any web app or service that uses a username/password login system should be storing their users’ passwords using a salted hash, possibly even a salted slow hash, perhaps with a pepper. If this is starting to sound more like breakfast than cryptography, don’t worry: unlike your password (hopefully), secure password storage isn’t too difficult of a topic to crack.

Plaintext and basic encryption

password-storage-plaintext

Username Entered Password Stored form
UnwittingUser WeakPassword WeakPassword

Storing plaintext passwords in an Internet-connected database is a pretty bad idea: if the database gets hacked, anyone who has reused one of those passwords is now at risk. And yet a disturbing number of websites still do it, probably because security upgrades are more for the customer than the company. If you want to test whether a site is doing this, try selecting the “forgot password” option. If they just send you your password instead of a reset link, it’s being stored in plaintext.

Username Entered Password Encrypted with AES-128 Key: WeakKey
UnwittingUser WeakPassword 38MkoXVXoKe01uAOROBLpQ==

Encryption may sound like a strong way to store passwords, but it’s really just a step above plaintext. An encrypted password can generally be decoded with a key, and if the hackers can find or guess it, the encryption is useless.

Hashing > encryption

password-storage-hashing

Username Entered Password String to be hashed Hashed with SHA-256
UnwittingUser WeakPassword WeakPassword 252E2406732308F9A7
B378ED94E78467D14
077D19C8282443FCD
3D6190FCABFA

A hash function is basically just one-way encryption: you convert the plaintext password to a secret code, but there’s no key to convert it back, meaning you can never derive the actual password from the hashed version.

This is how most secure websites manage their passwords:

  1. The user creates an account
  2. The user’s password is run through the hash function and stored in the database
  3. Every time the user logs in, the database hashes the password they entered and checks to see if the entered hash matches the hash they have on file.
  4. If yes, the user can log in

With a hash, the app/site never stores your actual password anywhere, and a hacker who breaks in will only get a list of letters and numbers that can’t be decoded. Depending on how strong the algorithm is, these hashes can be pretty difficult to crack.

Hashes aren’t hackproof, though. All an attacker has to do is run a dictionary of potential passwords through the hash function, then compare those hashes to the hashes in the database. When two hashes match, the hacker can just look at which password generated that hash.

To save time and computing power, many attackers just use a lookup table (or a “rainbow table,” a space-saving version of lookup tables), a pre-generated table full of potential passwords and their hashes. You can actually try hashing a plaintext word and then use a lookup table on the hash yourself; it’s not too hard. Essentially, if your password is at all common, the hash of that password is probably already in a lookup table. This is a great reason not to use common passwords.

Salted hashes > hashes

password-storage-salt

Username Entered Password String to be hashed Hashed with SHA-256,
salt = XcyKn42, prepended
UnwittingUser WeakPassword XcyKn42WeakPassword 13EB660FF7FBD29A728FC5
92297D78DF19AFF8797363
15FBF1F1C4B7123BD10C

Unlike slugs, salt makes hashes stronger. Since the entire hash changes even if just one letter of the plaintext word is changed, all a site needs to do to foil lookup tables is add some extra plaintext to the password before it’s hashed. The attacker will be able to read the plaintext salt since it’s stored in the database, but it forces them to recompute every possible combination of potential passwords and salts.

Of course, salted hashes can still be cracked. Hackers can just add the salt to the password they’re guessing, hash the combination, and wait for matches to pop up – a standard dictionary attack. Since modern GPUs can make billions of guesses per second, this isn’t at all infeasible, but it does make the process a lot more annoying. Failing that, brute-force attacks are slow but very effective.

Making hashes even stronger: other tactics

password-storage-pepper

Username Entered Password String to be hashed Hashed with Bcrypt,
salt = XcyKn42, prepended,
12 rounds
UnwittingUser WeakPassword XcyKn42WeakPassword $2y$12$6OleutQBO2iPoNvg
pyDndOU26Lqt9Y34f6PLEOx
mCELP5GoswrJT.

Slow hashing algorithms, like PBKDF2 or bcrypt, use a technique known as “key stretching” to slow down dictionary and brute force attacks. This essentially involves setting the hash function to iterate a certain number of times (though it’s a bit more complex than just running the same thing over and over again), so that in order to reach the correct hash you have to use a lot of computing power. If a site is doing all this, their security is pretty good.

Username Entered Password String to be hashed Hashed with Bcrypt,
salt = XcyKn42, prepended,
12 rounds,
pepper = |4|\/|@p3pp3r, appended
UnwittingUser WeakPassword XcyKn42WeakPassword|4|\/|@p3pp3r $2y$12$njmWr5UMydCzdCE44ElW/
OIfYp2PH9sgonCATyVY.OVKSpmoSaZlu

For added security, you can also “pepper” your hashes – which hopefully are already salted. A pepper, like a salt, is a set of values attached to the password before it is hashed. Unlike a salt, however, there is only one pepper value, and it is kept secret, separate from the salts and hashes. It adds another layer of security to the salted hash, but if the attacker manages to find it, it’s no longer very useful since the attacker can just use it to compute new lookup tables.

Don’t make a hash of your hash

Password security has made some big advances – and so has the art of cracking that security. Unfortunately, humans are still bad at password management, and databases don’t upgrade security as often as they should. In general, assume that whenever you create an account, the password is being stored with relatively weak security. If your password is common or a dictionary word, then it’s at a pretty high risk of being cracked. Make your passwords long, mixing letters, numbers, and symbols, and you’ll be helping hash functions do their best work.

Image credits: Hash function

Subscribe to our newsletter!

Our latest tutorials delivered straight to your inbox