Sunday, February 05, 2017

SHA256.Create() and "Works on my machine" FIPS-compliance

I've just had an interesting run-in with a little-advertised and not backwards-compatible feature in .net 4.6 and up, and how it affects FIPS-compliance, for those of us who have to worry about such things.

You see, in the recent .net versions (unlike the older ones), the selection of the default implementation toggles on whether the machine has HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy\[Enabled] set non-zero or not (or the equivalent group policy), and will select a FIPS-certified implementation for SHA256 (and SHA384 and SHA512), and, interestingly only for those flavours of SHA-2, using exactly the same criterion as is used to make the non-compliant implementations raise an exception on construction. So, assuming no app or machine level overrides, the matrix looks like this:

SHA###.Create()
no FIPS enforcementFIPS enforced
.net 4.6 and up

(Dev machine)
SHA###Managed

OK
SHA###Cng

"Works on my machine."
.net 4.5.2 or earlier

(Slow-moving customer environment)
SHA###Managed

OK
SHA###Managed

KABOOM!

The end-stop selection of algorithm defaults (where not overridden by a specific [class].Create()) in .net 4.5.2 are drawn from mscorlib alone, many FIPS-compliant, with the notable exceptions being the "new" (SHA-2, or AES which is present only by the original name of Rijndael), or old-and-deprecated (like MD5) algorithms. As in most cases, [DerivedClass].Create() is just a synonym for [BaseAlgorithm].Create(), you can get a false sense of security here -- SHA256CryptoServiceProvider.Create() will equally spit out an instance of SHA256Managed in three of the cases above, and SHA256Cng in the fourth ("works on my machine").

TL;DR -- if you have to worry about FIPS, don't use [Algorithm].Create(), but select the one you mean by calling its constructor explicitly.


Post a Comment