1 //------------------------------------------------------------------------------
2 // <copyright file="SecureStringHasher.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
9 using System.Collections.Generic;
10 using System.Diagnostics;
11 using System.Reflection;
12 using System.Security;
14 using System.Security.Permissions;
17 namespace System.Xml {
19 // SecureStringHasher is a hash code provider for strings. The hash codes calculation starts with a seed (hasCodeRandomizer) which is usually
20 // different for each instance of SecureStringHasher. Since the hash code depend on the seed, the chance of hashtable DoS attack in case when
21 // someone passes in lots of strings that hash to the same hash code is greatly reduced.
22 // The SecureStringHasher implements IEqualityComparer for strings and therefore can be used in generic IDictionary.
23 internal class SecureStringHasher : IEqualityComparer<String> {
25 delegate int HashCodeOfStringDelegate(string s, int sLen, long additionalEntropy);
27 // Value is guaranteed to be null by the spec.
28 // No explicit assignment because it will require adding SecurityCritical on .cctor
29 // which could hurt the performance
31 static HashCodeOfStringDelegate hashCodeDelegate;
33 int hashCodeRandomizer;
35 public SecureStringHasher() {
36 this.hashCodeRandomizer = Environment.TickCount;
39 #if false // This is here only for debugging of hashing issues
40 public SecureStringHasher( int hashCodeRandomizer ) {
41 this.hashCodeRandomizer = hashCodeRandomizer;
45 public bool Equals( String x, String y ) {
46 return String.Equals( x, y, StringComparison.Ordinal );
49 [SecuritySafeCritical]
50 public int GetHashCode( String key ) {
51 if (hashCodeDelegate == null) {
52 hashCodeDelegate = GetHashCodeDelegate();
54 return hashCodeDelegate(key, key.Length, hashCodeRandomizer);
58 private static int GetHashCodeOfString( string key, int sLen, long additionalEntropy ) {
59 int hashCode = unchecked((int)additionalEntropy);
60 // use key.Length to eliminate the rangecheck
61 for ( int i = 0; i < key.Length; i++ ) {
62 hashCode += ( hashCode << 7 ) ^ key[i];
65 hashCode -= hashCode >> 17;
66 hashCode -= hashCode >> 11;
67 hashCode -= hashCode >> 5;
71 [SecuritySafeCritical]
73 [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
75 private static HashCodeOfStringDelegate GetHashCodeDelegate() {
76 // If we find the Marvin hash method, we use that
77 // Otherwise, we use the old string hashing function.
79 MethodInfo getHashCodeMethodInfo = typeof(String).GetMethod("InternalMarvin32HashString", BindingFlags.NonPublic | BindingFlags.Static);
80 if (getHashCodeMethodInfo != null) {
81 return (HashCodeOfStringDelegate)Delegate.CreateDelegate(typeof(HashCodeOfStringDelegate), getHashCodeMethodInfo);
84 // This will fall through and return a delegate to the old hash function
85 Debug.Assert(false, "Randomized hashing is not supported.");
87 return new HashCodeOfStringDelegate(GetHashCodeOfString);