How to detect UseRandomizedStringHashAlgorithm? RRS feed

  • Question

  • .NET Framework 4.5 and later can be configured to use a randomized string hashing algorithm. How can a managed-code library check whether the framework is using such an algorithm?

    A library of ours has a legacy feature that unfortunately depends on String.GetHashCode returning the same hash codes even on different machines. The legacy feature is now disabled by default. If an application attempts to enable the legacy feature in an application domain where String.GetHashCode uses a randomized algorithm, I'd like the library to throw an exception saying that the legacy feature is not supported in that configuration.

    I can think of these solutions:
    • Call "test".GetHashCode() and check that the result is 0xEAE38E77 in a 32-bit process or 0xCC127386 in a 64-bit process. There is a small risk that the result matches even if randomized hashing is enabled, but it is extremely likely that a mismatch would be found during testing of the application.
    • Check for the UseRandomizedStringHashAlgorithm element in the application configuration file. This seems a bad solution because there are at least four other ways to enable randomized string hashing: environment variable, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, and AppDomainSetup.SetCompatibilitySwitches.
    • Call the private method String.UseRandomizedHashing() by reflection. Nobody guarantees it will still be there in future versions of the .NET Framework.

    I'm leaning towards the first solution. Do you have better ideas?

    Tuesday, October 6, 2015 5:57 PM

All replies

  • If you choose the first approach, then use more than one test string. Perhaps find a series of strings (demonstrating the vulnerability), which justified the new hashing algorithms.

    Tuesday, October 6, 2015 7:06 PM
  • I don't see any need for more than one test string. If the hashing algorithm is properly randomized, then the probability of an accidental match is only 2^(-32) ≈ 2.3E-10. If the application is tested ten times before release to market, then the probability that the hash code matches every time is 2^(-320) ≈ 4.7E-97. The test team would almost certainly get the exception.
    Tuesday, October 6, 2015 7:17 PM
  • The hashing algorithm can (and has in the past) changed with a .NET version upgrade. This approach might get a false positive simply because the computer running the code happens to have a version of .NET with a different algorithm. Your best bet is to just fix the dependency.
    Tuesday, October 6, 2015 9:17 PM
  • Applications using older versions of the library have saved the hash codes to persistent storage. If such an application is later upgraded to e.g. .NET Framework 9.0 and that computes different hash codes for strings, then it will not interoperate with the previously saved hash codes. As this configuration would cause the same problems as a randomized string hashing algorithm, I think throwing the same exception will be OK.

    Because of the saved hash codes, fixing the dependency would require porting the string hashing algorithm from CLR 4 to our library. At that time, we could also let the application specify whether the saved hash codes were computed with the 32-bit or 64-bit version of the CLR 4 algorithm, regardless of the bitness of the application process. This seems technically feasible but until it is implemented, I think it's best to throw the exception.

    You write that the hashing algorithm has changed with a .NET version upgrade in the past. If you can give a list of the versions in which those changes were made, that will be helpful.

    Wednesday, October 7, 2015 10:00 AM
  • I don't have a list of versions where it changed, it's just not something it kept track of.

    The first time it happened (that I am aware of), I was not involved in the investigation (it caused a number of test failures in our automated test system due to invalid assumptions). Based on the seating arrangements at the time, I can say we had long since migrated to .NET 2 but had not migrated to .NET 4. This means that the change was introduced by .NET 3, 3.5 or a hot fix, but since .NET 2, 3 and 3.5 all use the same runtime and mscorlib, it would seem reasonable that all three versions would have been equally affected.

    The second time something like this happened (that I am aware of), it affected a colleagues computer but not the build server. Both computers were producing consistent results for the same string, just not the same results. We were using a mix of 4.5.x versions but 4.6 had not been released back then.

    If you want to continue using GetHashCode, then that's a decision for you and your team. Personally, I would aim for a controlled migration.

    Wednesday, October 7, 2015 9:13 PM
  • Is it possible that the hash code mismatches in your environment were caused by differences between 32-bit and 64-bit versions of mscorlib, and not by any .NET Framework upgrade?

    Were you using String.GetHashCode(), rather than something like StringComparer.CurrentCultureIgnoreCase.GetHashCode(String)?

    Wednesday, October 7, 2015 9:32 PM