Update! I’ve updated a few points below in bold and have corrected a few things too
This blog post is the result of a thread on Twitter which starts here: https://twitter.com/crumpled_jeavon/status/880522105795870720 and works its way into confusion. Suffice to say I can’t answer these questions in 140 chars so here’s re-cap in the form of Q and A about Machine Keys and Umbraco. Please note that I am not an expert in hashing algorithms, some of these answers are based on my own research. Hope this clears things up!
How is the password hashed?
Jeffrey Schoemaker has been discussing updating Umbraco’s default password hashing to use an even stronger hash algorithm and I’ve recently updated a new task on the issue tracker to research this but it really comes down to the fact that Microsoft does not offer the best stronger hashing method in it’s standard .NET Framework so we’ll see where we end up.
Update – we will be shipping umbraco with stronger password hashing, possibly in a 7.7.x release http://issues.umbraco.org/issue/U4-10089 and it will use HMACSHA1 + PBKDF2 which is what ASP.NET Identity uses by default.
Is the Machine Key used for password hashing?
Yes, In 7.6.0+ it is by default because useLegacyEncoding is false by default in this release. Previous to 7.6.0 the useLegacyEncoding value was true by default purely to preserve some backwards compatibility settings for other products but you’ve been able to set it to true from 7.0.0 (IIRC). Since those products support the more secure password formats, this is now false by default and should be kept as false for new installs. By default the hashing algorithm is HMACSHA256 which uses comes from the ASP.NET Machine Key to perform part of it’s hashing function ‘validation’ algorithm type. This ‘validation’ algorithm type is configurable via the Machine Key or it is configurable at the membership provider level which would override the algorithm specified in the Machine Key, but you really shouldn’t change this to be a lesser strength hashing algorithm.
The HMAC part of this algorithm means it’s derived from a keyed algorithm and uses a key to generate the hash and the machine key is used to create this key by default. There doesn’t seem to be any documentation or reference to this online that I can find but trying to look through the crypto source code (which isn’t nice to look at) it seems that the default key gets set based on some logic in the RSACryptoServiceProvider class which reads some info from the machine key.
Update – the key used to hash the passwords is the generated salt we produce it is not the key part of the Machine Key. This logic is exactly the same as the logic used in the (DefaultMembershipProvider) and SqlMembershipProvider and if the hashing algorithm key length doesn’t equal the generated salt key length then it is padded/trimmed to the correct length, see source here. The part of the Machine Key that is used to hash the passwords is specifically the algorithm type. As you can see on this machine key generator, there can be a handful of different algorithm types used for the ‘validation’ part of a machine key and the default of this value changes based on the ASP.NET version being used. In ASP.NET 4.5 the default is HMACSHA256. Also note that in ASP.NET 4.5 the following algorithms are no longer allowed in the Machine Key config: AES, 3DES, and MD5
Do machine keys change between environments?
If you explicitly generate and set your own machine key in your web.config then the answer is No.
If you don’t explicitly generate and set your own machine key than you will get an auto-generated machine key. The simple answer for this is: In most cases No, an auto-generated machine key will not change between environments.
To understand when it will change between environments is a little more complicated and comes down to a combination of IIS user, IIS website virtual path (i.e. if you are running a site in a virtual directory), and a combination of a few settings set at the machine config level: “IsolateApps” and “IsolateByAppId”. Unless a server administrator specifically changes these settings than chances are you won’t be affected by different auto-generated machine keys for your site. If you are really keen, here’s a series all about this topic and other cryptographic changes in .NET 4.5:
- Part 1 – see the “A brief digression: auto-generated machine keys” for info on auto-generating keys
- Part 2 – in-depth info about the machine key and hashing changes
- Part 3 – interesting info especially with regards to PBKDF2 in .NET Framework
Update – another reason a machine key may change between environments is based on which version of ASP.NET is running and what it’s default ‘validation’ algorithm type is
Can I change my machine key?
However, I realize In some cases you might need to change it or move from an auto-generated machine key to an explicit machine key. If that is the case there will may be a lot of some manual work you’ll need to do. If you simply just change the machine key or add an explicit one when you previously didn’t have one than your members/users will might not be able to log in! This really comes down to what hashing algorithm was used originally to hash the passwords and what hash algorithm is configured in your Machine Key. If you install or change a machine key to a different algorithm that was used to first hash your passwords, then your members/users will not be able to log in.
Update – Previously I was under the impression that the key in the hashing algorithm was directly affected by the key in the machine key but after some more investigation it is not actually the case. As mentioned in the above updates, the part of the Machine Key that is used in the password hashing is the algorithm type specified (if you haven’t overridden this algorithm type by specifying it directly on the membership provider). I’ve also detailed some of this investigation in this ticket: http://issues.umbraco.org/issue/U4-10222
Can I change from useLegacyEncoding ‘true’ to ‘false’?
This will require a bit of extra work just like the above question but it’s not quite as tricky as changing a Machine Key. When you have useLegacyEncoding=’true’ , the machine key validation algorithm is not used, so you could do something like:
- Create a new password column in the database which will store the newly hashed password based on the new machine key validation algorithm
- When a user logs in you can check if they have the new password format or not.
- If not, then you can validate the password based on the old format then re-hash with the new format and store it and delete the old stored hash password.
- If so, then you can validate the password based on the new format
- To do this would probably require inheriting from the current Umbraco membership provider and implementing this logic yourself
Do I need to generate and store a custom Machine Key if I am planning on Load Balancing?
This is also mentioned in the Umbraco docs for load balancing
Do I need to generate and install a Machine Key before I run the Umbraco installer?
This is because during the Umbraco installation it will hash and store the password for the admin account and if you then add a Machine Key after the fact, you will no longer be able to log in.
Can Umbraco generate a custom Machine Key on install for me?
but it doesn’t do that right now. I created that functionality in a PR but we decided to remove the machine key generation part when it was accepted. We have decided to bring it back though so that will be part of an upcoming Umbraco release, whether that is the 7.6.x series or 7.7 series is still being decided.
Update – this is shipping with 7.7 and new installs will have a Machine Key generated and installed for you. You can of course opt out of this in the advanced installer options if you like.
Do Machine Key’s exist in ASP.NET Core?
Well sort of but not really. I haven’t been able to research too much into this but when speaking to a couple MS Dev’s about this a couple years ago the answer was that the way machine key’s work will be different. If keys need to be shared between apps in ASP.NET Core the data protection APIs need to be used and these keys would then be stored in the registry or the Cloud (i.e. Azure Key Vault), here’s a SO article on this.
Clear as mud?! ;)