【问题标题】:How can I generate a Guid from a SHA-1 byte array?如何从 SHA-1 字节数组生成 Guid?
【发布时间】:2013-08-24 02:35:55
【问题描述】:

我有这个代码来生成一个 SHA-1 哈希:

SHA1 sha1 = SHA1CryptoServiceProvider.Create();
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString);
Byte[] hash = sha1.ComputeHash(myStringBytes);

有没有办法将hash 转换为 Guid(我猜是类型 5,以与 SHA-1 保持一致)?

【问题讨论】:

  • 这有点令人困惑,因为哈希和 guid 是不同的东西。每次您请求新的 guid 时,guid 都应该给您一个唯一/不同的字符串。哈希会根据相同的输入为您提供一致的结果。
  • 它将是一个确定性和可重复的 GUID,基于散列,旨在根据输入生成唯一值。更多信息:waterjuice.org/2013/06/type-3-and-5-guids
  • @Justin:您误解了 OP 的要求。 GUID 只不过是一个全局唯一标识符;这就是 GUID 的含义。有很多方法可以生成 GUID。例如,您可以根据当前时间和位置制作 GUID;这是全球独一无二的。 (大多数情况下。)这是一种类型的 GUID。您可以使用随机数生成器制作统计上唯一的 GUID;那是第四类 GUID。 唯一字符串的加密强哈希也是唯一性来源,可用于构造 GUID。
  • @EricLippert 但你不会有机会与哈希与正确的 GUID 发生冲突。
  • @Justin:首先,类型 5 GUID 是“正确的”GUID。如果您要问“4 类随机 GUID 和 5 类 SHA 哈希 GUID 之间是否有可能发生冲突?”那么答案显然是“否”,因为它们的版本号必须不同!

标签: c# guid sha1


【解决方案1】:

正如 Justin 所指出的,Guid 每次都应该是唯一的,而哈希每次都会为相同的值提供一致的结果。

现在我想补充一点,Guid 和哈希(如果不是所有算法的话,大多数算法)都会发生冲突,尽管我的直觉是哈希比 Guid 更容易发生冲突。 ..虽然这可能取决于哈希的大小(即 128 位、256 位、512 位等)。

您会遇到的另一个问题是来自 SHA1 哈希的 byte[] 长度为 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[] 数据中应该没有实际变化。

【讨论】:

  • 首先,您误解了为什么使用唯一字符串的加密强度哈希来生成 GUID 是明智的。见我上面的评论。其次,这段代码是错误的;它不设置 GUID 的版本号,这是 GUID 格式的书面要求。
  • @EricLippert,在此处查看文本:en.wikipedia.org/wiki/… - 鉴于这表明 GUIDv5 是 SHA1,已从 160 位截断为 128 位,我猜我的第一个代码示例更接近OP的要求比我的第二个例子? - 大概这里还需要更多的返工来设置版本号?
【解决方案2】:

您可以基于rfc4122 使用此C# code。

为了防止link rot,这里有一些代码:

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;
}

【讨论】:

    猜你喜欢
    • 2018-11-08
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    相关资源
    最近更新 更多