我有这个代码来生成一个 SHA-1 哈希:
SHA1 sha1 = SHA1CryptoServiceProvider.Create();
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString);
Byte[] hash = sha1.ComputeHash(myStringBytes);
有没有办法hash
变成一个 Guid(我猜是类型 5,与 SHA-1 一致)?
为了防止链接腐烂,这里有一些代码:
public static Guid Create(Guid namespaceId, string name)
{
if (name == null)
throw new ArgumentNullException("name");
// convert the name to a sequence of octets (as defined by the standard or conventions of its namespace) (step 3)
// ASSUME: UTF-8 encoding is always appropriate
byte[] nameBytes = Encoding.UTF8.GetBytes(name);
// convert the namespace UUID to network order (step 3)
byte[] namespaceBytes = namespaceId.ToByteArray();
SwapByteOrder(namespaceBytes);
// comput the hash of the name space ID concatenated with the name (step 4)
byte[] hash;
using (HashAlgorithm algorithm = SHA1.Create())
{
algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0);
algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length);
hash = algorithm.Hash;
}
// most bytes from the hash are copied straight to the bytes of the new GUID (steps 5-7, 9, 11-12)
byte[] newGuid = new byte[16];
Array.Copy(hash, 0, newGuid, 0, 16);
// set the four most significant bits (bits 12 through 15) of the time_hi_and_version field to the appropriate 4-bit version number from Section 4.1.3 (step 8)
newGuid[6] = (byte)((newGuid[6] & 0x0F) | (5 << 4));
// set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively (step 10)
newGuid[8] = (byte)((newGuid[8] & 0x3F) | 0x80);
// convert the resulting UUID to local byte order (step 13)
SwapByteOrder(newGuid);
return new Guid(newGuid);
}
/// <summary>
/// The namespace for fully-qualified domain names (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid DnsNamespace = new Guid("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for URLs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid UrlNamespace = new Guid("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for ISO OIDs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid IsoOidNamespace = new Guid("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
// Converts a GUID (expressed as a byte array) to/from network order (MSB-first).
internal static void SwapByteOrder(byte[] guid)
{
SwapBytes(guid, 0, 3);
SwapBytes(guid, 1, 2);
SwapBytes(guid, 4, 5);
SwapBytes(guid, 6, 7);
}
private static void SwapBytes(byte[] guid, int left, int right)
{
byte temp = guid[left];
guid[left] = guid[right];
guid[right] = temp;
}
正如 Justin 所指出的,Guid 每次都应该是唯一的,而哈希每次都会为相同的值提供一致的结果。
现在我想补充一点,Guid 和哈希(如果不是所有算法的话,大多数算法)都会发生冲突,尽管我的直觉是哈希比 Guid 更容易发生冲突……尽管这可能取决于散列的大小(即 128 位、256 位、512 位等)。
您将遇到的另一个问题是byte[]
来自 SHA1 哈希的长度为 20 字节,而 Guid 长度为 16 字节,因此,从 SHA1 哈希创建 Guid 将不准确。
例子:
string myString = "Hello World";
SHA1 sha1 = SHA1CryptoServiceProvider.Create();
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString);
Byte[] hash = sha1.ComputeHash(myStringBytes);
Console.WriteLine(new Guid(hash.Take(16).ToArray()));
上面的示例将根据您的哈希创建一个 Guid,尽管它使用 LINQ 从哈希数组中获取 16 个字节(因此不准确......最后 4 个字节被简单地省略了)
MD5 是一个 16 字节的散列,所以这似乎比 SHA1 更适合转换为 Guid。
例子:
string myString = "Hello World";
MD5 md5 = MD5.Create();
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString);
Byte[] hash = md5.ComputeHash(myStringBytes);
Console.WriteLine(new Guid(hash));
这会从 MD5 散列生成准确的 Guid,尽管我会说,这一切都是 MD5 散列的 Guid 表示......数据中应该没有实际的变化byte[]
。