Skip to content

Commit d19bfe7

Browse files
Cease using cryptographic hashes
Under Windows, cryptographic hash may be rejected if FIPS is enabled and the used algorithm is not FIPS compliant. Fix #32 by the way
1 parent 511750a commit d19bfe7

File tree

14 files changed

+205
-165
lines changed

14 files changed

+205
-165
lines changed

CommonInternals/Hasher.cs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Derived from MurmurHash2Simple,
3+
* http://landman-code.blogspot.com/2009/02/c-superfasthash-and-murmurhash2.html
4+
*/
5+
6+
/***** BEGIN LICENSE BLOCK *****
7+
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
8+
*
9+
* The contents of this file are subject to the Mozilla Public License Version
10+
* 1.1 (the "License"); you may not use this file except in compliance with
11+
* the License. You may obtain a copy of the License at
12+
* http://www.mozilla.org/MPL/
13+
*
14+
* Software distributed under the License is distributed on an "AS IS" basis,
15+
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16+
* for the specific language governing rights and limitations under the
17+
* License.
18+
*
19+
* The Original Code is HashTableHashing.MurmurHash2.
20+
*
21+
* The Initial Developer of the Original Code is
22+
* Davy Landman.
23+
* Portions created by the Initial Developer are Copyright (C) 2009
24+
* the Initial Developer. All Rights Reserved.
25+
*
26+
* Contributor(s):
27+
*
28+
*
29+
* Alternatively, the contents of this file may be used under the terms of
30+
* either the GNU General Public License Version 2 or later (the "GPL"), or
31+
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32+
* in which case the provisions of the GPL or the LGPL are applicable instead
33+
* of those above. If you wish to allow use of your version of this file only
34+
* under the terms of either the GPL or the LGPL, and not to allow others to
35+
* use your version of this file under the terms of the MPL, indicate your
36+
* decision by deleting the provisions above and replace them with the notice
37+
* and other provisions required by the GPL or the LGPL. If you do not delete
38+
* the provisions above, a recipient may use your version of this file under
39+
* the terms of any one of the MPL, the GPL or the LGPL.
40+
*
41+
* ***** END LICENSE BLOCK ***** */
42+
43+
using System;
44+
using System.Text;
45+
46+
namespace NHibernate.Caches.Util
47+
{
48+
/// <summary>A stable hasher using MurmurHash2 algorithm.</summary>
49+
internal static class Hasher
50+
{
51+
internal static string HashToString(string input)
52+
{
53+
var hash = Hash(input);
54+
return hash.ToString("X");
55+
}
56+
57+
internal static uint Hash(string input)
58+
{
59+
return Hash(Encoding.UTF8.GetBytes(input));
60+
}
61+
62+
internal static uint Hash(byte[] data)
63+
{
64+
return Hash(data, 0xc58f1a7b);
65+
}
66+
67+
private const uint _m = 0x5bd1e995;
68+
private const int _r = 24;
69+
70+
internal static uint Hash(byte[] data, uint seed)
71+
{
72+
var length = data.Length;
73+
if (length == 0)
74+
return 0;
75+
var h = seed ^ (uint) length;
76+
var currentIndex = 0;
77+
while (length >= 4)
78+
{
79+
var k = BitConverter.ToUInt32(data, currentIndex);
80+
k *= _m;
81+
k ^= k >> _r;
82+
k *= _m;
83+
84+
h *= _m;
85+
h ^= k;
86+
currentIndex += 4;
87+
length -= 4;
88+
}
89+
90+
switch (length)
91+
{
92+
case 3:
93+
h ^= BitConverter.ToUInt16(data, currentIndex);
94+
h ^= (uint) data[currentIndex + 2] << 16;
95+
h *= _m;
96+
break;
97+
case 2:
98+
h ^= BitConverter.ToUInt16(data, currentIndex);
99+
h *= _m;
100+
break;
101+
case 1:
102+
h ^= data[currentIndex];
103+
h *= _m;
104+
break;
105+
}
106+
107+
// Do a few final mixes of the hash to ensure the last few
108+
// bytes are well-incorporated.
109+
110+
h ^= h >> 13;
111+
h *= _m;
112+
h ^= h >> 15;
113+
114+
return h;
115+
}
116+
}
117+
}

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Memcached/NHibernate.Caches.CoreDistributedCache.Memcached.csproj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
99
<SignAssembly>False</SignAssembly>
1010
<GenerateDocumentationFile>true</GenerateDocumentationFile>
11-
<PackageReleaseNotes>* New feature
12-
* #47 - Add an option for appending hashcode to key
13-
14-
* Task
15-
* #46 - Update NHibernate to 5.1.0</PackageReleaseNotes>
11+
<PackageReleaseNotes>* Improvement
12+
* #52 - Cease using cryptographic hashes</PackageReleaseNotes>
1613
</PropertyGroup>
1714
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
1815
<DefineConstants>NETFX;$(DefineConstants)</DefineConstants>

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Memory/NHibernate.Caches.CoreDistributedCache.Memory.csproj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ Meant for testing purpose, consider NHibernate.Caches.CoreMemoryCache for other
1010
<SignAssembly>True</SignAssembly>
1111
<AssemblyOriginatorKeyFile>..\..\NHibernate.Caches.snk</AssemblyOriginatorKeyFile>
1212
<GenerateDocumentationFile>true</GenerateDocumentationFile>
13-
<PackageReleaseNotes>* New feature
14-
* #47 - Add an option for appending hashcode to key
15-
16-
* Task
17-
* #46 - Update NHibernate to 5.1.0</PackageReleaseNotes>
13+
<PackageReleaseNotes>* Improvement
14+
* #52 - Cease using cryptographic hashes</PackageReleaseNotes>
1815
</PropertyGroup>
1916
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
2017
<DefineConstants>NETFX;$(DefineConstants)</DefineConstants>

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Redis/NHibernate.Caches.CoreDistributedCache.Redis.csproj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
<SignAssembly>True</SignAssembly>
1010
<AssemblyOriginatorKeyFile>..\..\NHibernate.Caches.snk</AssemblyOriginatorKeyFile>
1111
<GenerateDocumentationFile>true</GenerateDocumentationFile>
12-
<PackageReleaseNotes>* New feature
13-
* #47 - Add an option for appending hashcode to key
14-
15-
* Task
16-
* #46 - Update NHibernate to 5.1.0</PackageReleaseNotes>
12+
<PackageReleaseNotes>* Improvement
13+
* #52 - Cease using cryptographic hashes</PackageReleaseNotes>
1714
</PropertyGroup>
1815
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
1916
<DefineConstants>NETFX;$(DefineConstants)</DefineConstants>

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.SqlServer/NHibernate.Caches.CoreDistributedCache.SqlServer.csproj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
<SignAssembly>True</SignAssembly>
1010
<AssemblyOriginatorKeyFile>..\..\NHibernate.Caches.snk</AssemblyOriginatorKeyFile>
1111
<GenerateDocumentationFile>true</GenerateDocumentationFile>
12-
<PackageReleaseNotes>* New feature
13-
* #47 - Add an option for appending hashcode to key
14-
15-
* Task
16-
* #46 - Update NHibernate to 5.1.0</PackageReleaseNotes>
12+
<PackageReleaseNotes>* Improvement
13+
* #52 - Cease using cryptographic hashes</PackageReleaseNotes>
1714
</PropertyGroup>
1815
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
1916
<DefineConstants>NETFX;$(DefineConstants)</DefineConstants>

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache/Async/CoreDistributedCache.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
using System.Collections.Generic;
1414
using System.IO;
1515
using System.Runtime.Serialization.Formatters.Binary;
16-
using System.Security.Cryptography;
17-
using System.Text;
1816
using Microsoft.Extensions.Caching.Distributed;
17+
using NHibernate.Caches.Util;
1918
using NHibernate.Util;
2019

2120
namespace NHibernate.Caches.CoreDistributedCache

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache/CoreDistributedCache.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525
using System.Collections.Generic;
2626
using System.IO;
2727
using System.Runtime.Serialization.Formatters.Binary;
28-
using System.Security.Cryptography;
29-
using System.Text;
3028
using Microsoft.Extensions.Caching.Distributed;
29+
using NHibernate.Caches.Util;
3130
using NHibernate.Util;
3231

3332
namespace NHibernate.Caches.CoreDistributedCache
@@ -175,24 +174,18 @@ private static bool GetUseSlidingExpiration(IDictionary<string, string> props)
175174

176175
private string GetCacheKey(object key)
177176
{
177+
var baseKey = _cacheKeyPrefix + _fullRegion + ":" + key;
178178
var keyAsString = AppendHashcodeToKey
179-
? string.Concat(_cacheKeyPrefix, _fullRegion, ":", key.ToString(), "@", key.GetHashCode())
180-
: string.Concat(_cacheKeyPrefix, _fullRegion, ":", key.ToString());
179+
? baseKey + "@" + key.GetHashCode()
180+
: baseKey;
181181

182182
if (_maxKeySize < keyAsString.Length)
183183
{
184-
Log.Info(
185-
"Computing a hashed key for too long key '{0}'. This may cause collisions resulting into additional cache misses.",
186-
key);
187184
// Hash it for respecting max key size. Collisions will be avoided by storing the actual key along
188185
// the object and comparing it on retrieval.
189-
using (var hasher = new SHA256Managed())
186+
var hash = Hasher.HashToString(keyAsString);
187+
if (hash.Length > _maxKeySize)
190188
{
191-
var bytes = Encoding.UTF8.GetBytes(keyAsString);
192-
var computedHash = Convert.ToBase64String(hasher.ComputeHash(bytes));
193-
if (computedHash.Length <= _maxKeySize)
194-
return computedHash;
195-
196189
if (!_hasWarnedOnHashLength)
197190
{
198191
// No lock for this field, some redundant logs will be less harm than locking.
@@ -201,14 +194,29 @@ private string GetCacheKey(object key)
201194
"Hash computed for too long keys are themselves too long. They will be truncated, further " +
202195
"increasing the risk of collision resulting into additional cache misses. Consider using a " +
203196
"cache supporting longer keys. Hash length: {0}; max key size: {1}",
204-
computedHash.Length, _maxKeySize);
197+
hash.Length, _maxKeySize);
205198
}
206199

207-
keyAsString = computedHash.Substring(0, _maxKeySize.Value);
200+
hash = hash.Substring(0, _maxKeySize.Value);
208201
}
202+
203+
var toLongKey = keyAsString;
204+
keyAsString = keyAsString.Substring(0, _maxKeySize.Value - hash.Length) + hash;
205+
Log.Info(
206+
"Computed the hashed key '{0}' for too long cache key '{1}' (object key '{2}'). This may cause" +
207+
"collisions resulting into additional cache misses.",
208+
keyAsString, toLongKey, key);
209209
}
210210

211-
return _keySanitizer != null ? _keySanitizer(keyAsString) : keyAsString;
211+
if (_keySanitizer != null)
212+
{
213+
Log.Debug("Sanitizing cache key '{0}'.", keyAsString);
214+
keyAsString = _keySanitizer(keyAsString);
215+
}
216+
217+
Log.Debug("Using cache key '{0}' for object key '{1}'.", keyAsString, key);
218+
219+
return keyAsString;
212220
}
213221

214222
/// <inheritdoc />

CoreDistributedCache/NHibernate.Caches.CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ This provider is not bound to a specific implementation and require a cache fact
1010
<SignAssembly>True</SignAssembly>
1111
<AssemblyOriginatorKeyFile>..\..\NHibernate.Caches.snk</AssemblyOriginatorKeyFile>
1212
<GenerateDocumentationFile>true</GenerateDocumentationFile>
13-
<PackageReleaseNotes>* New feature
14-
* #47 - Add an option for appending hashcode to key
15-
16-
* Task
17-
* #46 - Update NHibernate to 5.1.0</PackageReleaseNotes>
13+
<PackageReleaseNotes>* Improvement
14+
* #52 - Cease using cryptographic hashes</PackageReleaseNotes>
1815
</PropertyGroup>
1916
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
2017
<DefineConstants>NETFX;$(DefineConstants)</DefineConstants>
@@ -23,6 +20,9 @@ This provider is not bound to a specific implementation and require a cache fact
2320
<None Include="..\..\NHibernate.Caches.snk" Link="NHibernate.snk" />
2421
<None Include="..\default.build" Link="default.build" />
2522
</ItemGroup>
23+
<ItemGroup>
24+
<Compile Include="..\..\CommonInternals\Hasher.cs" />
25+
</ItemGroup>
2626
<ItemGroup>
2727
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.0.0" />
2828
<PackageReference Include="NHibernate" Version="5.1.0" />

EnyimMemcached/NHibernate.Caches.EnyimMemcached/Async/MemCacheClient.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
using System;
1212
using System.Collections;
1313
using System.Collections.Generic;
14-
using System.Security.Cryptography;
15-
using System.Text;
1614
using Enyim.Caching;
1715
using Enyim.Caching.Memcached;
1816
using NHibernate.Cache;
17+
using NHibernate.Caches.Util;
1918
using Environment = NHibernate.Cfg.Environment;
2019

2120
namespace NHibernate.Caches.EnyimMemcached

0 commit comments

Comments
 (0)