Hashing messages using various hash algorithms in .NET

A hash of a message can be viewed as its unique identifier. A series of bytes, such as a string, can be converted into hash, also called a message digest. A message digest is also a byte array that can be converted into a base 64 string for better readability. There are various hashing algorithms out there that can calculate the hash of a message. Ideally each algorithm should produce a different digest for each message, i.e. “Hello world” should yield a different hash from what “H3llo world” produces. I.e. a single change in the byte sequence will change the resulting hash. Also, it should be impossible to calculate the original message from a hash. Therefore hashing is a one-way cryptographic operation.

Read more of this post

Advertisements

Hashing passwords with a password based key derivation function in .NET

In this post we saw a basic hashing technique using a password and a salt. We added an extra random set of bytes to the password and hashed the combined byte array instead of just the password bytes. We can store the salt along with the hash in our database. The main purpose of adding a salt to the password is to increase its entropy which more or less means randomness.

Hashing the password with an extra salt like that may still not be as secure as we think it is. The processing power of today’s fast computers and the increasing size of available rainbow tables keep pushing the limits of what’s available to crack with brute force attacks. One way to increase the difficulty of cracking a password is to keep hashing its hash in an iterative manner. Password-based key derivation functions help us achieve that and we’ll see an example of their usage in this post.

Read more of this post

Hashing passwords with a password based key derivation function in .NET

In this post we saw a basic hashing technique using a password and a salt. We added an extra random set of bytes to the password and hashed the combined byte array instead of just the password bytes. We can store the salt along with the hash in our database. The main purpose of adding a salt to the password is to increase its entropy which more or less means randomness.

Hashing the password with an extra salt like that may still not be as secure as we think it is. The processing power of today’s fast computers and the increasing size of available rainbow tables keep pushing the limits of what’s available to crack with brute force attacks. One way to increase the difficulty of cracking a password is to keep hashing its hash in an iterative manner. Password-based key derivation functions help us achieve that and we’ll see an example of their usage in this post.

Read more of this post

Hashing algorithms and their practical usage in .NET Part 2

In the previous post we looked at hashing in general and its usage in hashing query strings. In this post we’ll look at some other areas of applicability.

Passwords

Storing passwords in clear text is obviously not a good idea. If an attacker gets hold of your user data then it should not be easy for them to retrieve user names and passwords. It’s a well-established practice to store passwords in a hashed format as they cannot be deciphered. When your user logs onto your site the provided password is hashed using the same algorithm that was employed when the same user signed up with your site. The hashed values, i.e. not the plain text passwords will be compared upon log-in. Not even you as the database owner will be able to read the password selected by the user.

However, you must still be careful to protect the hashed passwords. As we mentioned in the previous post there are not too many hashing algorithms available. So if an attacker has access to the hashed passwords then they can simply get a list of the most common passwords – ‘secret’, ‘password’, ‘passw0rd’, etc. – from the internet, iterate through the available hashing algorithms and compare them to the hashed values in your user data store. They can even write a small piece of software that loops through an online dictionary and hashes those words. This is called a “dictionary attack”. It’s only a matter of time before they find a match. Therefore it may not be a blocking point that an attacker cannot reverse a hashed password.

Hashing passwords can be done in the same way as hashing a query string which we looked at previously. Here comes a reminder showing how to hash a plain text value using the SHA1 algorithm:

byte[] textBytes = Encoding.UTF8.GetBytes("myPassword123");
SHA1 hashAlgorithm = new SHA1Managed();
byte[] hash = hashAlgorithm.ComputeHash(textBytes);
string hashedString = BitConverter.ToString(data);

Salted passwords

So you see that storing hashed values like that may not be secure enough for the purposes of your application. An extra level of security comes in the form of salted passwords which means adding some unique random data to each password. This unique data is called ‘salt’. So we take the password and the salt and hash their joint value. This increases the work required from the attacker to perform a dictionary attack against all passwords. They would need to compute salt values as well.

Again, keep in mind that if you don’t protect your user data store then the attacker will gain access to the salt values as well and again it will be a matter of time before they find a match. It may take longer of course but they can concentrate on some specific valuable accounts, like the Administrator, instead of spending time trying to find the password of a ‘normal’ user.

This is how you can generate a salt:

private static string GenerateSalt(int byteCount)
{
	RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
	byte[] salt = new byte[byteCount];
	rng.GetBytes(salt);
	return Convert.ToBase64String(salt);
}

You’ll need cryptographically strong salt values. One of the available strong random number generators in .NET is the RNGCryptoServiceProvider class. Here we’re telling it that we need a ‘byteCount’-length of random salt. The salt is then saved along with the computed hash in the database.

The extended ComputeHash method accepts this salt:

public static string ComputeHash(string password, string salt)
{
	SHA512Managed hashAlg = new SHA512Managed();
	byte[] hash = hashAlg.ComputeHash(Encoding.UTF8.GetBytes(password + salt));
	return Convert.ToBase64String(hash);
}

So when the user logs in then you must first find the user in the database for the given username. If the user exists, then you have to retrieve the salt generated at the sign-up phase. Finally take the password provided in the login form, compute the hash using the ComputeHash method which accepts the salt and compare the hashed values.

We can add an extra layer or security by providing entropy – a term we mentioned in the previous post. We can extend the ComputeHash method as follows:

public static string ComputeHash(string password, string salt, string entropy)
{
	SHA512Managed hashAlg = new SHA512Managed();
	byte[] hash = hashAlg.ComputeHash(Encoding.UTF8.GetBytes(password + salt + entropy));
	return Convert.ToBase64String(hash);
}

The entropy can be a constant that is common to all users, e.g. another cryptographically strong salt that is not stored in the user database. We can take a random value such as ‘xl1k5ss5NTE=’. The updated ComputeHash function can be called as follows:

string salt = GenerateSalt(8);
Console.WriteLine("Salt: " + salt);
string password = "secret";
string constant = "xl1k5ss5NTE=";
string hashedPassword = ComputeHash(password, salt, constant);

Console.WriteLine(hashedPassword);
Console.ReadKey();

Alternatively you can use a Keyed Hash Algorithm which we also discussed in the previous post.

Examples from .NET

The .NET framework uses hashing in a couple of places, here are some examples:

  • ViewState in ASP.NET web forms is hashed using the MAC address of the server so that an attacker cannot tamper with this value between the server and the client. This feature is turned on by default.
  • ASP.NET Membership: if you have worked with the built-in Membership features of ASP.NET then you’ll know that both the username and password are hashed and that a salt is saved along with the hashed password in the ASP.NET membership tables
  • Minification and boundling: if you don’t know what these terms mean then start here. Hashing in this case is used to differentiate between the versions of the bundled files, such as JS and CSS so that the browser ‘knows’ that there’s a new version to be collected from the server and not use the cached one

We’ll start looking at symmetric encryption in the next post.

You can view the list of posts on Security and Cryptography here.

Hashing algorithms and their practical usage in .NET Part 1

Introduction

Cryptography is an exciting topic. It has two sides: some people try to hide some information and some other people try to uncover it. The information hiding, i.e. hiding some plain text, often happens using some encryption method. Then you have hackers, security experts and the like that try to decrypt the encrypted value.

Hashing is one such encryption algorithm. It converts some string input which can vary in size into a fixed length value, also called a “digest” or a “data fingerprint”. It’s called a fingerprint because the encrypted value can represent data that is much larger in size. You can take an entire book and create a short hash value out of its entire text.

Hashing is a one-way encryption method that cannot be deciphered (reversed) making it a standard way for storing passwords and usernames.

Note that in the demos I’ll concentrate on showing functionality, I won’t care about design practices and principles – that’s beside the point and it’s up to you to create the proper abstractions and services in your own solution. E.g. static helper classes shouldn’t be the norm to create services, but they are very straightforward for demo purposes. You’ll find many recommendations in among my glob posts on how to orginise your classes into loosely coupled elements.

I’ll concentrate on various topics within cryptography in this and the next several blog posts:

  • Hashing
  • Symmetric encryption
  • Asymmetric encryption
  • Digital signatures

After that we’ll take a look at a model application that makes use of asymmetric and symmetric encryption techniques.

Hashing in .NET

Common hash algorithms derive from the HashAlgorithm abstract base class. The most important concrete implementations out of the box include:

  • MD5 which creates a 128 bit hash – this algorithm is not considered secure any more so use it only if you need to ensure backward compatibility
  • SHA – Secure Hash Algorithm which comes in different forms: SHA1 (160bit), SHA256, SHA384 and SHA512 where the numbers correspond to the bit size of the hash created – the larger the value the harder it is to compromise the hashed value.
  • KeyedHashAlgorithms (Message Authentication Code): HMACSHA and MACTripleDES

Demo: plain text hashing

Open Visual Studio and create a new Console application. Enter the following code in Main:

string plainTextOne = "Hello Crypto";
string plainTextTwo = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

SHA512Managed sha512 = new SHA512Managed();

byte[] hashedValueOfTextOne = sha512.ComputeHash(Encoding.UTF8.GetBytes(plainTextOne));
byte[] hashedValueOfTextTwo = sha512.ComputeHash(Encoding.UTF8.GetBytes(plainTextTwo));

string hexOfValueOne = BitConverter.ToString(hashedValueOfTextOne);
string hexOfValueTwo = BitConverter.ToString(hashedValueOfTextTwo);

Console.WriteLine(hexOfValueOne);
Console.WriteLine(hexOfValueTwo);
Console.ReadKey();

So we use the most secure version of the SHA family, the one that creates a 512 bit hash. We take a short and a long string to demonstrate that the hash size will be the same. The ComputeHash method will return a byte array with 64 elements, i.e. 64 bytes which is exactly 512 bits. This method accepts a byte array input hence the call to the GetBytes method. We then show a hex string representation of the byte arrays. You’ll see in the console output that this string is grouped into 2 hex characters per byte. Each pair represents the byte value of 0-255. This is typical behaviour of the BitConverter class. There are other ways though to view a byte array in a string format.

You’ll also see that the hashed value length is the same for both strings. I encourage you to change those strings, even by only a single letter, and you’ll see very different hashed values every time.

Other hash algorithms in .NET work in a similar way:

  • MD5CryptoServiceProvider
  • SHA1Managed
  • SHA256Managed
  • SHA384Managed
  • SHA512Managed
  • MACTripleDES
  • HMACMD5
  • HMACSHA256
  • HMACMD5
  • HMACRIPEMD160
  • HMACSHA512

These are all concrete classes that derive from HashAlgorithm and implement the ComputHash(byte[]) method. All of them are quite fast. Actually SHA512Managed is among the fastest among the implementations so you don’t need to worry about execution speed if you go for this very strong algorithm.

Demo: tamperproof query strings

You must have seen websites that have URLs with some long and – at first sight – meaningless query string parameters. The goal is often to construct tamperproof query strings to protect the integrity of the parameters such as a customer id. The goal is make sure that this parameter has not been modified on the client side. Note that the actual ID will still be visible in the query string, e.g. /Customers.aspx?cid=21 but we extend this URL to include a special hash: /Customers.aspx?cid=21&hash=sdfhshmfuismfsdhmf. If the client modifies either the ‘cid’ or the ‘h’ parameter then the request will be rejected.

It’s customary to use a Hash-based Message Authentication Code (HMAC), not one of the other hashing algorithms. It computes the hash of a query string when constructed on the server. When the client sends another request to the server we check that the query string was not modified by comparing it to the original hashed value. If they don’t match then we know that the client or a man-in-the-middle has tampered with the query string values and reject the request.

We’ll also use a key so that the attacker wouldn’t be able to create his own valid hash – which is why HMAC is the better choice.

Create an ASP.NET web forms app in Visual Studio. Insert a hyperlink server control somewhere on Default.aspx:

<asp:HyperLink ID="lnkAbout" runat="server">Go to about page</asp:HyperLink>

Add a new helper class called HashingHelper. Insert the following public constants:

public static readonly string _hashQuerySeparator = "&h=";
public static readonly string _hashKey = "C2CE6ACD";

The hash query separator stores the hash param identifier in the query string. The key will be used to stop an attacker from creating an own hash as mentioned above.

The following method will create the hashed query:

public static string CreateTamperProofQueryString(string basicQueryString)
{
	return string.Concat(basicQueryString, _hashQuerySeparator, ComputeHash(basicQueryString));
}

…where ComputeHash is a private method within this class:

private static string ComputeHash(string basicQueryString)
{
        byte[] textBytes = Encoding.UTF8.GetBytes(basicQueryString);
	HMACSHA1 hashAlgorithm = new HMACSHA1(Conversions.HexToByteArray(_hashKey));
	byte[] hash = hashAlgorithm.ComputeHash(textBytes);
	return Conversions.ByteArrayToHex(hash);
}

…where Conversions is a static utility class:

public static class Conversions
{
	public static byte[] HexToByteArray(string hexString)
	{
		if (0 != (hexString.Length % 2))
		{
			throw new ApplicationException("Hex string must be multiple of 2 in length");
		}

		int byteCount = hexString.Length / 2;
		byte[] byteValues = new byte[byteCount];
		for (int i = 0; i < byteCount; i++)
		{
			byteValues[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
		}

		return byteValues;
	}

	public static string ByteArrayToHex(byte[] data)
	{			
        	return BitConverter.ToString(data);
	}
}

This will look familiar from the previous demo. We’re using a keyed algorithm – HMACSHA1 – which is based on SHA1 but can accept a key in the form of a byte array. Hence the conversion to a byte array in the Conversions helper.

In the Default.aspx.cs file add the following code:

protected void Page_Load(object sender, EventArgs e)
{
	if (!IsPostBack)
	{
		lnkAbout.NavigateUrl = string.Concat("/About.aspx?", HashingHelper.CreateTamperProofQueryString("cid=21&pid=43"));
	}
}

Run the project and hover over the generated link. You should see in the bottom of the web browser that the cid and pid parameters have been extended with the extra ‘h’ hash parameter.

Add a label control somewhere on the About page:

<asp:Label ID="lblQueryValue" runat="server" Text=""></asp:Label>

Put the following in the code behind:

protected override void OnLoad(EventArgs e)
{
	HashingHelper.ValidateQueryString();
	base.OnLoad(e);
}

…where ValidateQueryString looks as follows:

public static void ValidateQueryString()
{
	HttpRequest request = HttpContext.Current.Request;

	if (request.QueryString.Count == 0)
	{
		return;
	}

	string queryString = request.Url.Query.TrimStart(new char[] { '?' });

	string submittedHash = request.QueryString["h"];
	if (submittedHash == null)
	{
		throw new ApplicationException("Querystring validation hash missing!");
	}

	int hashPos = queryString.IndexOf(_hashQuerySeparator);
	queryString = queryString.Substring(0, hashPos);

	if (submittedHash != ComputeHash(queryString))
	{
		throw new ApplicationException("Querystring hash value mismatch");
	}
}

We retrieve the current HTTP request and check its query string contents. If there are no query strings then there’s nothing to validate. We then extract the entire query string bar the starting ‘?’ character from the URL. We check if any hash parameter has been sent – if not then we throw an exception. We then need to recompute the hash of the cid and pid parameters and compare that value with what’s been sent in the URL. If they don’t match then we throw an exception.

Run the application and click the link on the Home page. You’ll be directed to the About page. On the About page modify the URL in the web browser: change either query string parameter, reload the page and you should get an exception saying the hash values don’t match.

Why did we use a keyed algorithm? Let’s see first what may happen if you use a different one. In HashingHelper.ComputeHash comment out the line that creates a HMACSHA1 object and add a new line:

SHA1 hashAlgorithm = new SHA1Managed();

Run the application and you’ll see that it still works fine, the hashed value is generated and compared to the submitted value. Try changing the query parameter values and you should get the same exception as before. An attacker will look at this URL will know that this is some protected area. They will quickly figure out that this is some type of hash and they’ll start going through the different hash algorithms available out there. There aren’t that many – look at the list above with the ones built-into -.NET. It’s a matter of a couple of lines to generate hash values in a console app:

SHA1 hashAlgorithm = new SHA1Managed();
//calculate hash of cid=123&pid=32
//convert to string
//call the web site

If it doesn’t work then they’ll try a SHA256 and then SHA512 etc. It doesn’t take too long for an experienced hacker to iterate through the available implementations and eventually find the correct algorithm. They can then look at any protected value on the About page by replacing the query parameters and the hash they calculated using the little console application.

With the keyed algorithm we built in an extra blocking point for the attacker. So now the attacker will need to know the key as well as the hashing algorithm.

However, in some situations this may not be enough. If the query string parameter values are limited, such as a bit param 0 or 1 then even the keyed hash value will always only have two values: one for ‘0’ and another one for ‘1’. An attacker that’s watching the web traffic can after some time figure out what a ‘0’ hash and a ‘1’ hash looks like and they won’t need to deal with any secret keys.

Therefore we need some way to differentiate between two requests with the same parameter. We need to add some randomness to our hashing algorithm – this is called adding some “entropy”. In ASP.NET we can use the IP address of the client, their user agent, the session information and other elements that can differentiate one request from another. This is how you can add the unique session key to the data that’s being hashed:

HttpSessionState httpSession = HttpContext.Current.Session;
basicQueryString += httpSession.SessionID;
httpSession["HashIndex"] = 10;

Add this to the beginning of the HashingHelper.ComputeHash method. This will ensure that it’s not only ‘0’ or ‘1’ being hashed but some other information as well that varies a lot and is difficult to get access to. You can test it with the current setup as well. Run the application and you’ll get some hash in the query string. Stop the app, change the browser type in the Visual Studio app bar:

Change browser type in visual studio

Make sure it’s different from what you had in the previous run. Click the link on the default page and you should see that the hash value is different for the same combination of cid and pid query string values.

You can view the list of posts on Security and Cryptography here.

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT BEST PRACTICES WITH MICROSOFT STACK & ANGULAR

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: