2016-07-04 134 views
0

在我正在处理的项目中,我需要生成16个字符长的唯一ID,由10个数字和26个大写字母组成(只有大写字母)。必须保证它们具有普遍的独特性,并且不会有重演的机会。将唯一的16位数字ID映射到唯一的字母数字ID

这些ID不会永久存储。经过一段时间后,ID会从数据库中抛出,并且必须生成新的唯一ID。身份证不能重复扔出去的人。

因此,随机生成16位数字并检查先前生成的ID列表不是一种选择,因为没有全面的先前ID列表。另外,UUID将不起作用,因为ID必须是16位数字。

现在我正在使用16位唯一ID,它们在每次生成时都保证是通用唯一的(我使用timestamps生成它们以及唯一的服务器ID)。不过,我需要的ID很难预测,并且使用timestamps可以很容易地预测。

因此,我需要做的是将我有的16位数字ID映射到更大范围的10位数字+ 26个字母而不会失去唯一性。我需要某种散列函数,从一个较小的范围,以一个更大的范围映射,保证一个一对一的映射,使得唯一ID是保证被映射后留独特的。

我已经搜查,到目前为止还没有发现,保证是无冲突的任何哈希或映射功能,但如果我映射到一个更大的空间,一个必须存在。任何建议表示赞赏。

+0

保证当你不存储以前的这些问题时具有普遍独特性,这会造成问题。任何关于您一生中期望生成多少个ID的想法?例如,如果您使用mac地址和时间戳,并使用AES加密对其进行加密,则使用base-64对其进行编码,并采用可能有效的每个其他字母或数字。但是,它不能保证是唯一的。 –

+0

那么16位数时间戳+服务器ID保证在世代时是通用唯一的,而不是根据列表进行检查,问题是将其映射到更大的范围以使其“模糊化”而不会失去唯一性。你对AES加密的建议会带走唯一性,所以我不能使用它。 – watermelon82

+0

如何确保两个16位ID不会重复,如果它们是由同一服务器上的两个线程在同一时刻生成的? –

回答

0

编辑:这是一个更新的答案,因为我误解了对最终ID的限制。

这是一个可能的解决方案。

设置:

  • UID16 = 16位唯一ID
  • LUID = 16的码元的UID(使用数字+字母)
  • SECRET =秘密串
  • HASH =一些散列SECRET + UID16的现在

,你可以计算:

LUID = BASE36(UID16) + SUBSTR(BASE36(HASH), 0, 5) 

BASE36(UID16)将产生一个11个字符的字符串(因为16 /日志10(36)〜= 10.28)

它保证是唯一的,因为原始UID16被完全包含在最终的ID。如果碰巧与两个不同的UID16发生散列冲突,则仍然有两个不同的LUID。

然而,这是很难预测,因为5个其他符号是基于不可预测的哈希值。

注意:你只能得到的log 2(36^5)〜=散列部分,根据您的安全要求可能会或可能没有足够的熵的26位。原始UID16的可预测性越差越好。

+0

LUID也必须是16个字符。不能比这更长。 – watermelon82

+0

我明白了。我误读了“10位数字+26个字母”。 – Arnauld

0

您想要将由不同值组成的空间映射到具有36 值的空间。

这两个空格的大小比例为~795,866,110

使用BigDecimal并将每个输入值乘以比率,以便在输出空间上平均分配输入键。然后base-36对结果值进行编码。

下面是一个由11位数字“时间戳”和5位数字服务器ID组成的16位数字值的示例,使用上述方案编码。

Decimal ID   Base-36 Encoding 
---------------- ---------------- 
4156333000101044 -> EYNSC8L1QJD7MJDK 
4156333000201044 -> EYNSC8LTY4Y8Y7A0 
4156333000301044 -> EYNSC8MM5QJA9V6G 
4156333000401044 -> EYNSC8NEDC4BLJ2W 
4156333000501044 -> EYNSC8O6KXPCX6ZC 
4156333000601044 -> EYNSC8OYSJAE8UVS 
4156333000701044 -> EYNSC8PR04VFKIS8 
4156333000801044 -> EYNSC8QJ7QGGW6OO 

前11位数字组成了“时间戳”,我计算了一系列增加1的结果;最后五位数字是任意的“服务器ID”,在这种情况下是01044

0

Brandon StaggsImplementing a Partial Serial Number Verification System上写了一篇好文章。这些示例用Delphi编写,但可以转换为其他语言。

+0

尽管这个链接可能回答这个问题,但最好在这里包含答案的基本部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 - [来自评论](/ review/low-quality-posts/12908105) – willome

0

您的问题的一个通用解决方案是加密。由于加密是可逆的,因此它始终是从明文到密文的一对一映射。如果您对数字[0,1,2,3,...]进行加密,那么只要保留相同的密钥,不要重复数字或溢出允许的大小,就可以保证所得到的密文也是唯一的。您只需跟踪下一个要加密的数字,根据需要递增,并检查它是否永远不会溢出。

然后问题降低到加密的大小(以位为单位)以及如何将其作为文本呈现。你说:“10个数字加26个大写字母(只有大写字母)。”这与Base32编码相似,后者使用数字2,3,4,5,6,7和26字母。不完全符合你的要求,但可能足够接近现成的产品。每Base32字符5个字符的16个字符是80位。您可以使用80位块密码并将输出转换为Base32。您可以滚动您自己的简单Feistel cipher或使用Hasty Pudding cipher,它可以设置为任意块大小。如果这里有一个重要的安全要求,请不要推出自己的产品。你自己的Feistel密码会给你独特性和迷惑,而不是安全性。冬笋布丁也具有安全性。

如果你确实需要所有的10位数字和26个字母,那么你正在查找基数为36的数字。计算出36^16所需的位数,然后继续。将密文比特转换为基数36表示的数字。

如果你编写自己的密码,那么看起来你不需要解密函数,这将节省一些工作。