Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Core / SecureStringHasher.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SecureStringHasher.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
7
8 using System;
9 using System.Collections.Generic;
10 using System.Diagnostics;
11 using System.Reflection;
12 using System.Security;
13 #if !SILVERLIGHT
14 using System.Security.Permissions;
15 #endif
16
17 namespace System.Xml {
18
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> {
24         [SecurityCritical]
25         delegate int HashCodeOfStringDelegate(string s, int sLen, long additionalEntropy);
26         
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
30         [SecurityCritical]
31         static HashCodeOfStringDelegate hashCodeDelegate;
32
33         int hashCodeRandomizer;
34
35         public SecureStringHasher() {
36             this.hashCodeRandomizer = Environment.TickCount;
37         }
38
39 #if false // This is here only for debugging of hashing issues
40         public SecureStringHasher( int hashCodeRandomizer ) {
41             this.hashCodeRandomizer = hashCodeRandomizer;
42         }
43 #endif
44
45         public bool Equals( String x, String y ) {
46             return String.Equals( x, y, StringComparison.Ordinal );
47         }
48
49         [SecuritySafeCritical]
50         public int GetHashCode( String key ) {
51             if (hashCodeDelegate == null) {
52                 hashCodeDelegate = GetHashCodeDelegate();
53             }
54             return hashCodeDelegate(key, key.Length, hashCodeRandomizer);
55         }
56         
57         [SecurityCritical]
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];
63             }
64             // mix it a bit more
65             hashCode -= hashCode >> 17; 
66             hashCode -= hashCode >> 11; 
67             hashCode -= hashCode >> 5;
68             return hashCode;
69         }
70         
71         [SecuritySafeCritical]
72 #if !SILVERLIGHT
73         [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
74 #endif
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.
78  
79             MethodInfo getHashCodeMethodInfo = typeof(String).GetMethod("InternalMarvin32HashString", BindingFlags.NonPublic | BindingFlags.Static);
80             if (getHashCodeMethodInfo != null) {
81                 return (HashCodeOfStringDelegate)Delegate.CreateDelegate(typeof(HashCodeOfStringDelegate), getHashCodeMethodInfo);
82             }
83      
84             // This will fall through and return a delegate to the old hash function
85             Debug.Assert(false, "Randomized hashing is not supported.");
86
87             return new HashCodeOfStringDelegate(GetHashCodeOfString);
88         }
89     }
90 }