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:
|no FIPS enforcement||FIPS enforced|
|.net 4.6 and up|
"Works on my machine."
|.net 4.5.2 or earlier|
(Slow-moving customer environment)
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.