How to not make a hash of your passwords with Scrypt.NET

I wasn’t aware until I began writing this article that the phrase “to make a hash of something” was in common use in the English-speaking world today.

According to the Cambridge Dictionary, to make a hash of something can be interpreted as follows.

hash noun (FAILURE)
make a hash of sth [ S ] UK informal

to do something very badly:
[e.g.] He made a complete hash of the last question.

In my part of the world, we frequently use this term when something has been done incorrectly and in the context of password storage, unfortunately, it seems to be all too easy to get it wrong.

There are many articles available online which already explain the concept of encryption versus hashing, so I don’t want to bore you with too many details regarding this discussion (hint: you should not be encrypting user account passwords!). Rather I will concentrate only on the key points for the benefit of those who are not as familiar with the topic.

If you are already ‘au fait’ with password security concepts, press here to skip to the Scrypt.NET section of the article.

Password Hashing

Suffice to say salted password hashing is the approach that you should employ whenever you need to store user account passwords. It offers the best and the only truly viable protection for the scenario and it helps to limit damage in the unfortunate event of unauthorised access to your user account store.

So, let’s back up a bit. Let’s say you are implementing the user account creation/sign-up page for your application; you will want to take the password entered by the new user and store it, for example, in a database. In simple terms when it comes to saving the password you should take the plain-text value which was entered and apply a hash function to it before you store it.

Hashes are one-way computations resulting in a non-reversible value, unlike encrypted values which can be decrypted with a secret key. Note that it is very important that a cryptographic hashing function such as SHA256 or SHA512 is used, along with a long, unique salt value.

What’s a Salt?

A salt is simply a long, random string which is used in conjunction with the password whenever a hash computation is made such that the resulting hash value cannot be predicted.

It is important that a fresh salt value is generated each time before computing a hash. By using a random salt value each time, the hash value will be different for every password that is hashed, even for the same password.

Consider the following sample password.

A8jQdu767x6*^sQ%4s6E

This is a very strong password and the SHA256 hash of it is as follows.

yaWHbFwPsSXTXKiaLNo/nBcDotKBNR1IGB38oRYeQTQ=

Looks pretty secure, right?

Wrong! The SHA256 hash of the above password will be the same every time this password is hashed and this is not good enough for user account password storage.

Ok, let’s be fair. Given that the password, in this case, is very strong, one could argue it’s not too bad for security, but we know for a fact that our users are not going to choose good passwords. Passwords are reused and shared and consequently, we will usually end up with more than one hash with the same value in our user account store.

Attackers have all sorts of tools in their arsenal for cracking passwords, such as password dictionaries and rainbow tables. These tools can allow the ill-intentioned to very quickly establish passwords by using a pre-computed list of hashes which are compared with the hashes that exist in their victim’s user account store. However, since an attacker can’t know what a randomised salt value will be in advance, a salt typically renders the aforementioned tools close to useless since the computed hash value is extremely unlikely to match any hashes from the attacker’s pre-computed list.

Pragmatism Reigns

There’s very little you can do to prevent brute force attacks where an attacker iterates through every possible character combination to arrive at the correct password, however, the idea behind your password storage strategy is to make it as impractical as possible for a password to be determined within a reasonable period of time.

In short, it is very easy to get password storage wrong so the key thing you should take away from this article is the following: Do not be tempted to implement your own hashing algorithm. Use tried and tested solutions which have been battle-tested and have stood the test of time.

See this OWASP Cheatsheet for more helpful information about password storage and salted hashes.

Introducing Scrypt.NET

When seeking to find a solution for securely storing passwords you’ll probably be wondering what password hashing algorithm you should use. When deciding this, it is a balance between opting for a very new algorithm which purports to be very secure, versus an algorithm which has been around for a while but may not be as strong today given the fact that computational power is always increasing.

Presently for me, it’s a toss-up between either ‘Argon’ or ‘scrypt’. The first version of the scrypt algorithm was published in 2009. There has since been a second version and in 2016 the scrypt algorithm was published by the IETF as RFC 7914, so it’s a nice balance between something which has both been around for a long time and has also in more recent times been accepted as a standard.

Scrypt.NET is a library written in C# which implements the ‘scrypt’ hashing algorithm and it is very easy to use.

Let’s dive in and see how it works.

First of all, install the Scrypt.NET NuGet package into your project.

Next, you’ll want to take a look at the key class within the library which contains the hashing functions you will be using. It is named ScryptEncoder and provides the following public methods.

  • Compare
  • Encode
  • IsValid

The Compare method is used to compare a plain string value with a hashed string value i.e. to check if the password entered by a user, when hashed, equals a stored hash value. If the hashed values match then the user should be granted access.

The Encode method accepts a plain string value and computes a hash for it. The Scrypt.NET library formats the computed value in such a way that the algorithm version and all other settings are embedded into the string which is returned. This helps to simplify the storage of the password without the need to store the settings or salt value in separate database columns, for example.

The IsValid method accepts a hashed string value and is used to check if the supplied string is a valid scrypt hash. It is sometimes useful to call this method against your stored password hash, before calling the Compare method.

Here is a very simple example of how to compute a hash for the sample password we looked at earlier.

var encoder = new ScryptEncoder();
 
string hash = encoder.Encode("A8jQdu767x6*^sQ%4s6E");
 
Console.WriteLine(hash);
 
// Sample output
// -------------
// $s2$16384$8$1$X9zfZ14kj4x39/xbxG/ApKhxm+t9vX95nYSk2NqrOXY=$QzT/fw9qAm798fYpKnkI9fQ862tldeJgzFK9Q5/R3+c=

You can see how Scrypt.NET nicely formats the hash output for us, using dollar signs to separate the individual values within the string. I have split out and described each part of the output below.

s2

The scrypt algorithm version.

16384

The number of hash iterations performed.

8

The amount of memory which will be required per hash iteration.

1

The number of parallel calculations required.

X9zfZ14kj4x39/xbxG/ApKhxm+t9vX95nYSk2NqrOXY=

The salt value.

QzT/fw9qAm798fYpKnkI9fQ862tldeJgzFK9Q5/R3+c=

The final hash value.

By formatting the hash output as described above, Scrypt.NET has everything it needs, later on, to validate and compare the stored hash with the hash output for a specified string.

We can check if a password entered by a user is valid by passing it as the first parameter to the Compare method and then passing the hash from our data-store as the second parameter, as per the code below.

bool hashMatches = encoder.Compare("A8jQdu767x6*^sQ%4s6E", hash);

In the above example, the specified hash will match the stored hash, assuming that the hash variable in the code snippet represents the hash output which was stored following a previous Scrypt.NET hash computation for the same password.

It really is this simple to get your password storage right, so there’s no excuse once you know that helpful libraries like Scrypt.NET exist. There are many libraries available for other languages which do a similarly brilliant job at storing your passwords safely, just be sure to do your research and check that the library that you choose has been peer-reviewed and is widely used by the community.

Wrapping Up

If you want to see some more code you can check out the Scrypt.NET GitHub repository. Within the Scrypt.NET project, you will find that all of the core functionality is encapsulated within the ScryptEncoder class which we have been discussing. It won’t take too long to look through the source so I would recommend investing the time to examine it fully so that you are aware of what is going behind the scenes whenever you use the library.

Additionally, I’ve created my own GitHub repository which contains a simple wrapper class around the Scrypt.NET methods to help simplify its usage even further and to demonstrate how the library works.

Comments

This site uses Akismet to reduce spam. Learn how your comment data is processed.