Passwords are a problem, as we frequently see in the news when databases containing password and login information are hacked and exposed.
Though too much security is never enough, as developers, there are things we can do to keep our users’ passwords secure.
The best way to not allow passwords to be compromised is to not store the password at all. Unfortunately, I’ve seen far too many apps that have databases with a “password” column that contains the actual password! And I’m sure you’ve seen web sites that, when you click the “forgot password” link, send you an email with your actual password! This is not good. The only one who should know the password is the person who created the password.
So the first thing to do is to not store the password. Instead store a one-way hash of a password. A hash is a function that given a value, returns a new value of a fixed length that is always the same for the original value. A one-way hash is a hash that can convert text to a hash value but cannot convert the hash value back to the original text.
It just so happens that Xojo has several built-in one-way hash functions in the Crypto namespace: MD5, SHA1, SHA256, SHA512 and PBKDF2.
For example, given a password “frenchfries”, MD5 generates this hash value (converted to hex):
The idea is that instead of storing the actual password, you use the hash of the password. To validate that the password is correct, when the user logs in you calculate the hash of the password they entered and then check to see if it matches the hash of the password you have stored. If they are the same then you know the password is correct even though you do not know the actual password.
This strategy is a great start, but it has a flaw: it is susceptible to a “brute-force” attack. This is where a nefarious hacker pre-calculates hash values for large amounts of common words. This is referred to as a rainbow table. Since most people choose relatively simple passwords, they will more than likely be found in a rainbow table. If a hacker gets access to your hash value and they know how it was calculated, they can then look it up in the rainbow table to see what the plain text password is.
One way to help mitigate this is to use a “salt” along with the password to create the hash. The salt is an extra value that you add to the password to generate hashes that make rainbow tables largely useless. You can use the same salt value for all the passwords or you can use something more specific for each password.
Creating an MD5 hash on the combination of the hash for “frenchfries” and the text “salted” generates this hash using MD5:
Such a value is not likely to show up in a rainbow table anywhere because it’s specific to you, thus limiting its general usefulness. A hacker would actually need to figure out how you are creating your salt value before they can generate a rainbow table.
Using a hash with a salt works well, but you also have to use a secure hashing function. It has been known for some time that MD5 and SHA1 are no longer secure hashing functions and are not recommended for use. The primary problem is that it is possible for two completely different values to generate the same hash. This flaw has been used to fake security certificates among other things. You may think it does not matter much for your purposes, but don’t be the one that is easier to hack. Use one of the other available hashing functions such as SHA256.
But even better, you can use the PBKDF2 function which is essentially a “slow” function which makes brute-force attacks more difficult to achieve. PBKDF2 with a salt and SHA256 can work really well. Here is an example:
Dim salt As Text = "salted" Dim saltData As Xojo.Core.MemoryBlock saltData = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(salt) Dim password As Text = "frenchfries" Dim passwordData As Xojo.Core.MemoryBlock passwordData = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(salt) hashData = Xojo.Crypto.PBKDF2(saltData, passwordData, 500, _ 32, Xojo.Crypto.HashAlgorithms.SHA256)
The resulting hash is a MemoryBlock so to display it, you’ll want to convert it to a hexadecimal value. This code can easily do that:
Private Function ConvertToHex(mb As Xojo.Core.MemoryBlock) As Text Dim hex As Text For b As Int8 = 0 To mb.Size - 1 hex = hex + mb.Int8Value(b).ToHex(2) Next Return hex End Function
The hash for “frenchfries” with the salt “salted” yields this hash value using the above PBKDF2 function:
Download the sample project to play around with the various hashing functions.
Updated (Oct 15, 2015) to ensure 2-digit hex values are used.