在 .Net 中生成唯一密钥






3.74/5 (64投票s)
2006年6月10日
3分钟阅读

440438

10202
我需要创建一些唯一的 ID。GUID 很棒,因为它们提供了全局唯一标识符,但它们很大。我的意思是,如果你想在你的应用程序中发布一个唯一的数字,你想把它作为预订号或任何参考号,那么 GUID 显然不是一个解决方案。
引言
我有几个应用程序,我需要在其中创建一些唯一的 ID。GUID 很棒,因为它们提供了全局唯一标识符,但它们很大。我的意思是,如果你想在你的应用程序中发布一个唯一的数字,你想把它作为预订号或任何参考号,那么 GUID 显然不是一个解决方案。因此,我需要一些简单的 ID,它们也是唯一的。例如,当我向我的信用卡处理器发送请求时,会有一个 ID 将我的发票与提供商的交易关联起来。在这里,GUID 不是我想要的。
但是一个相对简单的解决方案是创建顺序 ID,它的大小合适,并且也能保证唯一性。非常好且简单的解决方案!!!不是吗!!我的回答是否定的!!因为它对您的网站来说是一个安全威胁。在 Web 应用程序中,您可以通过仅提供订单参考号来检索您的订单或预订详细信息,您可以轻松地使用暴力破解顺序参考号来检索记录。
在本文中,我将讨论我的一些研究和技术。
使用 DateTime 和 HashCode
使用 DateTime 生成唯一密钥是一种非常常见的做法。我通过在其中引入 HashCode 来重新混合这种方法。比如
DateTime.Now.ToString().GetHashCode().ToString("x");
它会给你一些类似 496bffe0 的密钥。乍一看,它似乎满足了唯一密钥的要求,因为它使用当前时间和哈希来生成密钥,但 GetHashCode() 每次都不会产生唯一的代码。尽管 Microsoft 正在使用带有 N 个碰撞解决双哈希函数的双哈希算法,但在我的实验中,我发现了许多碰撞。
使用 GUID 和 HashCode
然后我尝试了
Guid.NewGuid().ToString().GetHashCode().ToString("x");
它给出的密钥类似于 649cf2e3
不知何故,我认为这种字符串表示至少不是唯一的……38 个字符表示为 8 个?好的,32 位,但它仍然是 8 位数字,字符仅限于十六进制值,是的,我的怀疑是正确的,因为我编写了一个程序,生成了 100,000 个密钥,并检查了碰撞,发现了一些重复的密钥。
使用 RNGCryptoServiceProvider 和字符掩码
.net Framework 提供了 RNGCryptoServiceProvider 类,该类使用密码服务提供程序 (CSP) 提供的实现来执行密码随机数生成器 (RNG)。此类通常用于生成随机数。虽然我可以在某种程度上使用这个类来生成唯一的数字,但它也不是无碰撞的。此外,在生成密钥时,我们可以通过使其成为字母数字而不是纯数字来使密钥更加复杂。所以,我将这个类与一些字符掩码一起使用,以生成固定长度的唯一密钥。以下是代码示例
private string GetUniqueKey() { int maxSize = 8 ; int minSize = 5 ; char[] chars = new char[62]; string a; a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; chars = a.ToCharArray(); int size = maxSize ; byte[] data = new byte[1]; RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider(); crypto.GetNonZeroBytes(data) ; size = maxSize ; data = new byte[size]; crypto.GetNonZeroBytes(data); StringBuilder result = new StringBuilder(size) ; foreach(byte b in data ) { result.Append(chars1)>); } return result.ToString(); }
分析
为了进行实验室测试,我使用上述三种方法创建了 1,000,000 个唯一密钥,并发现了以下结果
生成方法 |
所用时间 |
生成的密钥数量 |
重复密钥的数量 |
所有固定长度密钥 |
|
使用 DateTime 和 HashCode |
01.56 秒 |
10,00,000 |
500131 |
否 |
|
使用 GUID 和 HashCode |
04.45 秒 |
10,00,000 |
113 |
否 |
|
使用 RNGCryptoServiceProvider 和字符掩码
|
00.40 秒 |
10,00,000 |
0(哇!!) |
是 |
|
以上分析表明,带有字符掩码的 RNGCrypto 是生成唯一密钥的最佳方法。
注意:以上研究仅用于学习目的。是的,可能还有其他比上面提到的更好的方法。