| File: FrameworkFork\Microsoft.Xml\Xml\Core\SecureStringHasher.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Security; namespace Microsoft.Xml { // SecureStringHasher is a hash code provider for strings. The hash codes calculation starts with a seed (hasCodeRandomizer) which is usually // different for each instance of SecureStringHasher. Since the hash code depend on the seed, the chance of hashtable DoS attack in case when // someone passes in lots of strings that hash to the same hash code is greatly reduced. // The SecureStringHasher implements IEqualityComparer for strings and therefore can be used in generic IDictionary. internal class SecureStringHasher : IEqualityComparer<String> { [SecurityCritical] private delegate int HashCodeOfStringDelegate3(string s, int sLen, long additionalEntropy); [SecurityCritical] private delegate int HashCodeOfStringDelegate1(string s); // Value is guaranteed to be null by the spec. // No explicit assignment because it will require adding SecurityCritical on .cctor // which could hurt the performance [SecurityCritical] private static HashCodeOfStringDelegate3 s_hashCodeDelegate3; [SecurityCritical] private static HashCodeOfStringDelegate1 s_hashCodeDelegate1; private int _hashCodeRandomizer; public SecureStringHasher() { _hashCodeRandomizer = Environment.TickCount; } #if false // This is here only for debugging of hashing issues public SecureStringHasher( int hashCodeRandomizer ) { this.hashCodeRandomizer = hashCodeRandomizer; } #endif internal static SecureStringHasher Instance { get; } = new SecureStringHasher(); public bool Equals(String x, String y) { return String.Equals(x, y, StringComparison.Ordinal); } [SecuritySafeCritical] public int GetHashCode(String key) { if (s_hashCodeDelegate1 == null && s_hashCodeDelegate3 == null) { GetHashCodeDelegate(); } if (s_hashCodeDelegate1 != null) { return s_hashCodeDelegate1(key); } return s_hashCodeDelegate3(key, key.Length, _hashCodeRandomizer); } [SecurityCritical] private static int GetHashCodeOfString(string key, int sLen, long additionalEntropy) { int hashCode = unchecked((int)additionalEntropy); // use key.Length to eliminate the rangecheck for (int i = 0; i < key.Length; i++) { hashCode += (hashCode << 7) ^ key[i]; } // mix it a bit more hashCode -= hashCode >> 17; hashCode -= hashCode >> 11; hashCode -= hashCode >> 5; return hashCode; } [SecuritySafeCritical] private void GetHashCodeDelegate() { // If we find the Marvin hash method, we use that // Otherwise, we use the old string hashing function. // The Marvin hash method signature changed in netcore 2.1-pre to have a single argument and apparently was removed in 2.1 RTM. // Note: calling Type.GetMethod with the exact param types does not always work, need to get the method info and check the parameters. MethodInfo getHashCodeMethodInfo = typeof(String).GetMethod("InternalMarvin32HashString", BindingFlags.NonPublic | BindingFlags.Static); if (getHashCodeMethodInfo != null) { ParameterInfo[] paramTypes = getHashCodeMethodInfo.GetParameters(); if (paramTypes.Length == 1 && paramTypes[0].ParameterType == typeof(string)) { s_hashCodeDelegate1 = (HashCodeOfStringDelegate1)getHashCodeMethodInfo.CreateDelegate(typeof(HashCodeOfStringDelegate1)); } else if (paramTypes.Length == 3 && paramTypes[0].ParameterType == typeof(string) && paramTypes[1].ParameterType == typeof(int) && paramTypes[2].ParameterType == typeof(long)) { s_hashCodeDelegate3 = (HashCodeOfStringDelegate3)getHashCodeMethodInfo.CreateDelegate(typeof(HashCodeOfStringDelegate3)); } } if (s_hashCodeDelegate1 == null && s_hashCodeDelegate3 == null) { // This will fall through and return a delegate to the old hash function s_hashCodeDelegate3 = new HashCodeOfStringDelegate3(GetHashCodeOfString); } } } }