我们有一个用.NET编写的遗留系统,我们正在迁移到Node.js。
原始系统使用("some string value").GetHashCode()
根据用户数据生成一些令牌。
我正在寻找一种在JavaScript中实现此功能的方法,以便将系统的这一部分移植到Node.js。
因此,我对String.GetHashCode()
实际如何运作感兴趣。在某处记录了算法吗?它甚至是一个稳定的算法,还是在各种.NET版本中都有变化?
我试图找到有关其实施的一些细节,但这对我来说真的很难,因为.NET不是我的主要技术,而且我并不熟悉它的资源和信息来源。
答案 0 :(得分:1)
取自微软的Reference Source,其中一个实现是:
// Gets a hash code for this string. If strings A and B are such that A.Equals(B), then
// they will return the same hash code.
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override int GetHashCode() {
#if FEATURE_RANDOMIZED_STRING_HASHING
if(HashHelpers.s_UseRandomizedStringHashing)
{
return InternalMarvin32HashString(this, this.Length, 0);
}
#endif // FEATURE_RANDOMIZED_STRING_HASHING
unsafe {
fixed (char *src = this) {
Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
#if WIN32
int hash1 = (5381<<16) + 5381;
#else
int hash1 = 5381;
#endif
int hash2 = hash1;
#if WIN32
// 32 bit machines.
int* pint = (int *)src;
int len = this.Length;
while (len > 2)
{
hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
pint += 2;
len -= 4;
}
if (len > 0)
{
hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
}
#else
int c;
char *s = src;
while ((c = s[0]) != 0) {
hash1 = ((hash1 << 5) + hash1) ^ c;
c = s[1];
if (c == 0)
break;
hash2 = ((hash2 << 5) + hash2) ^ c;
s += 2;
}
#endif
#if DEBUG
// We want to ensure we can change our hash function daily.
// This is perfectly fine as long as you don't persist the
// value from GetHashCode to disk or count on String A
// hashing before string B. Those are bugs in your code.
hash1 ^= ThisAssembly.DailyBuildNumber;
#endif
return hash1 + (hash2 * 1566083941);
}
}
}
这在.NET版本中是不稳定的,并且在分散在string.cs源代码中的注释中,它在同一进程中的AppDomain之间甚至可能不稳定。
如果你想要一个真实,稳定的哈希码,可以“安全”地保存在AppDomain之外,请查看System.Security.Cryptography
中的哈希函数。 MD5
对于低安全性工作是可以接受的,SHAx
风格甚至更好。
True Hashes只是一种方式,不可能真正反转哈希,因为它是一个“有损”的过程。如果您获得代码的开发人员声称他们可以反转哈希,那么他们要么撒谎,要么弄错,要么没有实现正确的哈希。
答案 1 :(得分:1)
添加to Bradley's answer这是一个基于String.GetHashCode()
的64位实现的稳定哈希代码,它不使用我之前为答案编写的不安全代码。
public static class StringExtensionMethods
{
public static int GetStableHashCode(this string str)
{
unchecked
{
int hash1 = 5381;
int hash2 = hash1;
for(int i = 0; i < str.Length && str[i] != '\0'; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ str[i];
if (i == str.Length - 1 || str[i+1] == '\0')
break;
hash2 = ((hash2 << 5) + hash2) ^ str[i+1];
}
return hash1 + (hash2*1566083941);
}
}
}