Support for new ASP.NET password storage practices
#1
At present, the EPiServer pattern can be used against hashes generated by the ASP.NET membership provider. However, this is what's referred to as the SqlMembershipProvider which has now been somewhat deprecated by newer implementations.

It all gets a bit confusing, but in short there is a new pattern for MVC apps and another for web forms apps. I'd really like to write something up on the strength improvements (for one of them, anyway) and be able to do a back-to-back comparison of old and new.
Here's how they work:

For a new ASP.NET MVC4 app using the Visual Studio 2012 template, the SimpleMembershipProvider is used. This is also used in what Microsoft refers to as "ASP.NET WebPages" which have been around for a while now.

The hashing approach is explained here: http://stackoverflow.com/a/12545172/73948

From the comments in the code: "PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations."

The implementation of the hashing is here: http://aspnetwebstack.codeplex.com/Sourc...fCrypto.cs

In simple terms:
1. Generate the 128 bit salt and 256 bit subkey from the password using the Rfc2898DeriveBytes class with 1,000 iterations (implements PBKDF2): http://msdn.microsoft.com/en-us/library/...bytes.aspx
2. Create a byte array containing the salt then the subkey.
3. Base64 encode it all then store it in a single DB field.

This gives us "passwords" as follows (password, plain text):

AG8nVMgXdmjX+LVQUjrhNz1QFOt+S/wudjeeOSPyz/+cuXYtY12TrQqQ9SV2HnO0mA== password
AKmqIP8aQ3HepENus1wOKkHUG73OPFuVqhVOxzr4Ar6kMdMeOhA3tTEmeQ61gd+iWw== password
AB2OiyAI8LPgCHwk4VXxsaheWk7Ka/Yq2XGFX3FwlH/GUWKdTZFp0oKPWfOHNgRmpg== Password!
AHzkkhFXHZUCDzryniFjI3/LF4viZG0IY9PYMVlsakpkScnFZDWXRm7iTVBLAooHYA== Password!

For a new Web Forms app using the Visual Studio 2012 template, the DefaultMembershipProvider is used. It's pretty much the same deal hashing wise as with the old SqlMembershipProvider (and therefore the EPiServer pattern) but uses a SHA256 hash by default instead of SHA1 (although can be configured to use SHA1). Here's the process:

1. Generates a 128 bit salt.
2. Hash the password with SHA256.
3. Add the hash to the salt then Base64 encode it.
4. Base64 encode the salt.
5. Store both encoded values into separate DB fields.

This gives us "passwords" as follows (password, salt, plain text):

cfrhyZf2CHjZ/pI7TNUJXcxMqKy0nsmR6e9qY+mCmNk= JAtBUUstKzWYVJhxMfG3bQ== password
jYkIDI2hGqEZ4T7mlv7aqXqOQNiw13Nbq08UXkjZPIk= dXPGsSyHJ4FEmkfRsuGFsg== password
Hzxoixo/8Bx9AQfQ+b3DjSMAB09gSCYNa7Woxz4ar34= C9Zj7TZRWIBhhK3qlcrkEA== Password!
fEnbqvFsutQS1tONeCybK/HyfmSl+tDPKBOuyW/clQA= mdi0z0NpxSC6igdRGqm/Fw== Password!

All of this supersedes the SqlMembershipProvider which was ultimately just a single iteration of SHA1.

Caveat: this is from briefly browsing through mostly decompiled source code and I've not actually recreated the process myself. Originally, I'd been advised that the DefaultMembershipProvider implemented 1,000 iterations of SHA256 but evidence seems to be to the contrary. Hopefully this is easy enough to validate if you're able to put together a pattern for it. I'm happy to validate against a complete sample data set if you want a beta tester.
#2
Who thought that "PBKDF2_SHA1(pw, salt, 1000, 256)" is a good idea?
Because CPU hash crackers are going to:
* Checking the first 160 bits gets you 2x faster than defender.
* SSE2 gets you 4x faster than defender.
* Cached HMAC gets you 2x faster than defender (this might be used).
* AVX2 (q2 2013) will give you another 2x faster than defender.

Then there's GPUs...

Also 1000 was the minimum recommended 12 years ago.
#3
(11-15-2012, 06:20 AM)Sc00bz Wrote: Who thought that "PBKDF2_SHA1(pw, salt, 1000, 256)" is a good idea?

The same people who thought LM Hash and NT Hash were a good idea. Smile
#4
(11-15-2012, 08:12 AM)epixoip Wrote:
(11-15-2012, 06:20 AM)Sc00bz Wrote: Who thought that "PBKDF2_SHA1(pw, salt, 1000, 256)" is a good idea?

The same people who thought LM Hash and NT Hash were a good idea. Smile

I'm gonna have to give you both (Sc00bz & epixoip) a "like" for your comments there guys. :-)

But .. uhh. Troy? You know ASP.NET WAAAY better than I do. Can't you configure it to use other algorithms as well, with the above being the (new) default?
#5
(11-15-2012, 11:54 PM)thorsheim Wrote: But .. uhh. Troy? You know ASP.NET WAAAY better than I do. Can't you configure it to use other algorithms as well, with the above being the (new) default?

Not out of the box, what you see above are the defaults and that's what you get if you provision a brand new ASP.NET site.

Having said that, they implement a provider model which allows you to re-implement components without changing the interfaces to the rest of the app. You can head over to NuGet and pull down a package like Zetetic's which'll do 5,000 rounds of PBKDF2 or 2^10 rounds of bcrypt: http://nuget.org/packages/Zetetic.Security

Agree with all that it's way too weak by default. The universal provider with 1,000 rounds of PBKDF2 is certainly much better then the previous single round but still falls way short of where it needs to be. This is why I'd really like to see these patterns implemented so the respective risks of the various implementations can be quantified and developers can make their choices with all the facts in front of them.
#6
To be fair, PBKDF2(HMAC-SHA1, pw, salt, 1000, 256) is absolutely much better than the previous SHA1(pw, salt). Completely insufficent and quite silly, but still better than we had. PBKDF2(HMAC-SHA-3-256, pw, salt, 100000, 256) would of course be better, but Microsoft seems dead against PBKDF2 for anything other than SHA1.

Atom, I would be extremely interested in the addition of PBKDF2 (PKCS #5, RFC2898) hash iteration types, though as # of rounds can vary (and should vary - see https://www.owasp.org/index.php/Password...heat_Sheet), I'd strongly suggest making the # of rounds a parameter, preferably on a password by password basis, i.e.
roundsConfusedalt:password
1000Confusedssss:ppppppppppppppp
5000Confusedssss:ppppppppppppppp
64000Confusedssss:ppppppppppppppp
1000Confusedssss:ppppppppppppppp

More flexible still, and very useful would be to also support the output length in bits as a parameter.
#7
Working on getting at least the web forms added. Certainly not just base64 sha256($pass.$salt). But

[Image: asplode.jpg]