Almost every software has to deal with some kind of user/identity management – be it desktop applications that usually should integrate with the operating system’s and/or business environment’s identity and authentication concepts or be it cloud based/mobile applications or web services that need to be able to control access on their own behalf.

The issue will even become more important in the near future, because the number of mobile users grows at a high rate, and at the same time we can read almost every day about stolen passwords and hacked websites. Also, the activities of Intelligence services around the world don’t really make one feel more secure…

So, with mobile application development and cross-platform compatibility in mind, I fired up my favorite search engine and was looking for a password hashing implementation that met the following requirements:

  • PCL – compatible
  • Easy to use
  • And, of course, being cryptographically as secure as possible

To my surprise, I found nothing that met all the above requirements and was usable out of the box. What I did find were various different components, that had to be re-combined into a new class (called PasswordHash).

Generally, a lot can be found on the web about cryptography and password security. I especially liked this article, as it is very concise and straight to the point, and at the same time gives a good explanation about how passwords can be hacked – and therefore, to which aspects one should pay extra attention. I strongly suggest you this article when you’re interested in some basic knowledge about password security. In this post, I won’t go into details about these more general aspects, but focus on more .NET-specific issues and on basic usage of the PasswordHash class.

Creating a Hash

To create a strong hash from a password, you need to perform the following steps:

The API that I had in mind was as simple as this:

But when I tried out the C# sample code that was accompanying the aforementioned article, it didn’t compile into a .NET Portable Class Library, because the namespace System.Security.Cryptography is not supported in the .NET portable subset. So I needed to rewrite the code to make it PCL-compatible…

CSPRNG with Bouncy Castle

The first thing needed is a CSPRNG generator for PCLs. In standard .NET, you would use System.Security.Cryptography.RNGCryptoServiceProvider, but this is one of the pieces that are not available in .NET Portable Class Libraries. Here, Bouncy Castle comes to the rescue. Bouncy Castle is an OSS project that maintains a library which provides APIs all around cryptography. And best of all, there is a NuGet package for PCLs (called BouncyCastle-PCL) that we can use as a replacement for the missing standard .NET pieces. This is a possible implementation of a CSPRNG generation method using this package:

Generating the Hash

With this salt, the next thing would be to create a hash from the [password]:[salt] combination that we currently have. To do this, we use an implementation of the PBKDF2 algorithm, which is a standardized key derivation function. I found a Bouncy Castle implementation of this algorithm in the answer to this Stackoverflow question.

With the Pbkdf2 class in place, our hash creation function is as simple as this:

The return value from this method is in the format

and looks something like this:

This is the final string that we store together with the user’s name. It is variable along three dimensions:

  • Length (in bytes) of the salt
  • Length (in bytes) of the hash
  • The number of iterations, i.e. how often the PBKDF2 key derivation algorithm was repeatedly applied

These three dimensions are reflected through respective properties in the PasswordHash class.

Validating a Hash

The other operation that our PasswordHash class needs to support is hash validation. We need to be able to answer the question: Was the given hash generated from the specified password? So the signature of the other public operation of the PasswordHash class would be:

Validating a password/hash pair involves the following steps:

  • Retrieve the user’s hash and salt from the data store
  • Append the salt to the given password and hash it with the same hash function that was used to originally create the hash.
  • Compare this test hash to the one that was retrieved from the data store. If they match, the password is correct.

Following these steps, the complete implementation of the method is this:

(SlowEquals() is a special time-constant comparison function that participates in making the password hash more secure by hardening the validation algorithm against timing-based attacks.)

Points of Interest

There are mainly to aspects to the code presented here: (1) The hashes are completely random and (2) their creation parameters can vary.

Never use the same hash twice (except for internal validation)

One important aspect is, that the generated hashes are completely random. In other words: The CreateHash() function never generates the same hash twice for a given password. The following test (using xUnit.Net) exemplifies this:

Password/Hash Validation is Agnostic to Varying Hash Creation Parameters

Hash creation can vary along the dimensions salt-length, hash-length, and number of iterations. However, such a change does not affect password validation in any way, as long as the same algorithm is used for both hash creation and validation. This is demonstrated by the below test:

The sample solution

A small sample solution (VS 2013) containing the PasswordHash class and the above client code can be found here on GitHub. Note that the unit tests thereinare not meant to prove anything in a strict sense. Rather, they serve to demonstrate the usage and to reasonably verify that the code does what it should do.

Share on Pinterest
There are no images.
Share with your friends










Submit
Category:
Cross Platform Development, General C#/.NET
Tags:
, , ,
  • Martin Stoeckli

    After looking into the source, it looks to me as if SecureRandom is not reading from the random source of the OS and therefore is not seeded. Did you use the same class
    “Org.BouncyCastle.Security.SecureRandom” in your example?