Adding a custom hashAlgorithmType in C# ASP.NET
Asked Answered
P

3

3

I've got a page that I need to beef up security on. I'm using the built-in MembershipProvider functionality and currently have hashAlgorithmType set to SHA512. I've got the BCrypt.NET library (http://bcrypt.codeplex.com/) and it seems to be working nicely when I call its functions from code but I'm having the worst time figuring out how to create the appropriate <cryptographySettings> section in Web.config to let me create a hashAlgorithmType.

I found the following code snippet on the web:

<mscorlib>
    <cryptographySettings>
        <cryptoNameMapping>
            <cryptoClasses>
                <cryptoClass   MyHash="MyHashClass, MyAssembly
              Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
              Version=1.0.0.0"/>
                <cryptoClass   MyCrypto="MyCryptoClass, MyAssembly
              Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
              Version=1.0.0.0"/>
            </cryptoClasses>
            <nameEntry name="System.Security.Cryptography.HashAlgorithm"
                       class="MyHash"/>
        </cryptoNameMapping>
        <oidMap>
            <oidEntry OID="1.3.36.3.2.1"   name="MyCryptoClass"/>
        </oidMap>
    </cryptographySettings>
</mscorlib>

Call me a noob if you want, but I apparently don't have the requisite knowledge to make heads or tails of that. All I need is a method to tell the membership provider that something like <hashAlgorithmType="bcrypt"> corresponds to something like string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12)); to encrypt and bool matches = BCrypt.CheckPassword(candidate, hashed); to decrypt. Please tell me there's an easy answer. I can rewrite the login system from scratch if I have to, but I already have a working implementation that I'd really like to just change the hashing algorithm of.

Protract answered 23/6, 2011 at 21:17 Comment(5)
I would probably not be using BCrypt - I'd be sticking with SHA256+ and AES/Rijndael; Blowfish was a competitor for AES and Bruce Schneier, its designer, whilst being obviously bullish about how great it is, doesn't recommend people use it in preference to AES (Read Practical Cryptography). Just my 2 cents.Radian
Actually, I will self-correct, it wasn't a competitor for AES - that's Twofish; it's successor - also designed by Bruce Schneier (et al)Radian
BCrypt was chosen for good reasons and more importantly, not chosen by me - I just need to make it work, any idea how?Protract
Does BCrypt implement HashAlgorythm? If it does not you will have to modify BCrypt to implement it. Depending on the insides of BCrypt it can be a trivial task or (more likely) can be nothing short of a challenge.Sidonia
@zespri - I am coming to the same conclusion as I use google-fu (and am getting redirected back to SO most of the time!)Radian
R
3

I believe that config pattern must be applied to the machine.config file; which isn't necessarily a great move if you need to be able to roll out this code easily.

You can programmatically register the BCrypt encryption primitive(s) with the CryptoConfig class through a call to AddAlgorithm with a name that can you can later use.

So long as the BCrypt hash provider implements HashAlgorithn you should be able to register it simply, you can also test this by calling HashAlgorithm.Create(string) with the name you use to verify that it builds the algorithm correctly.

The membership provider should then be able to use it without issue. Here's a good article about this topic.

Update

(deep breath) - apologies if this is tl;dr.

Okay, so having read around about BCrypt.Net's password hashing - it's obviously good, and follows accepted practise. It is, also, completely incompatible with how the HashAlgorithm class works because it requires additional state in order to work it's magic, and can't simply be extended to implement the HashAlgorithm contract.

Thus, you have a choice - stick with MembershipProvider and use SHA512 as you already are - you're talking about beefing up security on a page, so I'm thinking there might be issues with authentication itself, rather than the storage of passwords (which must, of course, still be done properly) - so consider simply making sure that the authentication traffic is sent over HTTPS if it's not already.

Using password stretching algorithms blindly has its own issues - see the responses to my own recent SO on this topic - if you do the stretching on the server you could potentially end up causing a DOS attack on the site!

The other option is, as you've suggested, to manage the membership entirely yourself - thus you can use whichever types you want and manage the necessary storage of the password information manually.

My sites now use an algorithm very similar to PBKDF2 that I lifted from Bruce Schneier and Niels Ferguson's book Practical Cryptography, for which I use 512 bit random salt and SHA512 (storage is cheap) plus many thousands of iterations to hash a clear text. The server benchmarks itself once per appdomain to establish 'levels' of protection that equate to millisecond ranges - thus over time newly hashed passwords will receive a constant level of protection even if the hardware improves. The library is standalone, too, and I've been able to deploy it to SQL Server 2008 R2 to provide CLR SPs if we have to generate password records at the SQL level.

But this only protects the passwords - you then need an authentication mechanism that can protect the act of logging in; plus another system for protecting the authenticated session token (.Net's Authentication Cookie system is actually pretty good for this).

Following on from that SO I have now spent a week implementing SCRAM primitives that I have then plugged into my MVC web services for authentication, and I plan to do the same to enable login from the web browser using Javascript (locking out non-JS clients). The key there being the client is doing all the hash calculations; thus I've stuck to SHA because mature implementations are readily available in practically any environment (e.g. we have iPhone apps too - and they need to authenticate as well).

In your case, however, with the existing investment in the MembershipProvider, I would consider 512 bits of SHA plus SSL plus Asp.Net's auth cookie sufficient - so long as the database is really secure(!) and you've got no SQL injection holes in the site.

Radian answered 23/6, 2011 at 22:13 Comment(14)
Well the code is only being rolled out for one customer so editing machine.config might not be too bad of a solution. As for registering it programmatically, I've never had to do such a thing before. Do you know of somewhere I could find sample code or perhaps have a snippet yourself? I'm beginning to feel like I'm in way over my head on this and I'm about ready to just ditch ASP.NET's built-in membership provider and just do all the SQL, hashing and comparison myself...Protract
I don't think it implements HashAlgorithm... I added CryptoConfig.AddAlgorithm(typeof(BCrypt), "BCrypt"); and HashAlgorithm.Create("BCrypt"); to my code and I get: Unable to cast object of type 'project_name.BCrypt' to type 'System.Security.Cryptography.HashAlgorithm'.Protract
@David - first, you will feel like that, this is a small tip of a huge iceberg! I've lost count of how many times I've felt like this! You might be able to do it directly in your web site's web.config - either way, though, here's an article I've just found (blogs.msdn.com/b/shawnfa/archive/2008/12/02/cryptoconfig.aspx) its 3.5, but applies to v4 tooRadian
@David, Okay, so we need to see if there is a class in there that does implement it, I am sure there will be, or you could roll your own, possibly. I am on my phone at the moment, so tricky to browse codeplex easily for code, but I will see what I can do. Equally you could reflect the dll in ilspy/reflector or something like that, with the .net kind loaded too. Find the base .net hashalgorithm type and expand the 'derived types', see if any bcrypt types appear.Radian
Looks like I wouldn't be the first one to go hunting: #5643687Protract
No prob, I know how working from your phone can be, I just appreciate you taking the time to help.Protract
@David Yes and I find a Google search for BCrypt and membership provider yields this question as the top result! now that is some serious SEO on the part of SO!Radian
@David, thinking about it, you say you need to beef up the security on this page... bcrypt password protection, as I understand it, is based also on salts and stretching. This isn't quite the same as a straightforward hash and therefore won't lend itself to the HashAlgorithm class. In any case, it is designed to protect the storage of passwords; am I right in thinking the security you speak of here is more to do with the authentication exchange?Radian
@David - have updated my answer (with a bit of a novel); I think BCrypt and MembershipProvider are incompatible without a complete reimplementation of BCrypt and even then it's going to be difficult... So I have some (hopefully) words of received wisdom for you to help you move forward :)Radian
Yeah if my customer keeps demanding BCrypt I'll just have to rewrite the login system without using the membership provider, which is a giant pain but oh well. Thanks for all your help anyway!Protract
@David no problem! I have had endless pain but also endless fun learning about all this stuff, its a big learning curve but worth pursuing, especially if you absolutely have to, because its knowledge that will keep giving back every time you do a new project. It really isn't easy tho! Equally, I'm still no expert, have got about another twenty or thirty years to go before that ;)Radian
Hey, quick question in case you know (not in front of my work PC at the moment so can't do the easy test) - you mentioned Rijndael as a possible BCrypt competitor and I might be able to sell my customer on it as an alternative - is it as simple as hashAlgorithmType="Rijndael" or is there more involved?Protract
Hey @David, went bed sorry, on UK time. Ah yes I thought initially you were using bcrypt, or blowfish, in its capacity as a cipher, but as it has panned out,you weren't. It's going to be sha instead in this case.Radian
Gotcha. No problem at all, my client is in Finland so I'm getting kind of used to the time delays :DProtract
T
1

For a BCrypt implementation of HashAlgorithm, see my answer to a similar question here.

You would need to create a signed assembly with the sample code in my answer, and then modify your settings as needed:

<cryptoNameMapping>
  <cryptoClasses>
    <cryptoClass MyHash="BCryptHasher, MySignedAssemblyName
                 Culture=neutral, PublicKeyToken=<my public key for singed assembly>,
                 Version=1.0.0.0"/>
  </cryptoClasses>
  <nameEntry name="System.Security.Cryptography.HashAlgorithm" class="MyHash"/>
</cryptoNameMapping>
Tegular answered 12/7, 2011 at 15:23 Comment(0)
S
0

To be able to register a custom hashAlgorythmType, the first thing you need is a type that actually implements HashAlgorythm. If BCrypt implements it, it's your lucky day, but apparently it does NOT implement it, so this is your problem.

There is really no work around for it, as implementing HashAlgorithm is a requirement for being able to register it like this.

So what you are going to need to do is either write a wrapper around BCrypt to implement HashAlgorithm, or, of this is not possible, modify BCrypt itself to implement it.

Unless you are really-really lucky and BCrypt is written in a way that easily lend itself to such a modification, it can require some non-trivial efforts.

Sidonia answered 23/6, 2011 at 22:56 Comment(1)
@David the code you already tried should work, if the type implements HashAlgorithm then you won't get an InvalidCastException any more.Radian

© 2022 - 2024 — McMap. All rights reserved.