【问题标题】:Generate 1M unique random keys with alpanumeric subset生成具有字母数字子集的 1M 唯一随机密钥
【发布时间】:2012-06-18 16:23:51
【问题描述】:

我想生成 1M 随机(出现)唯一的字母数字键并将它们存储在数据库中。每个键的长度为 8 个字符,并且仅使用子集“abcdefghijk n pqrstuvxyz 和 0-9”。

字母 l、m、o 和 w 被丢弃。由于打印空间有限,省略了“m 和 w”,因为每个键都将在非常小的空间内打印在产品上。删除 m 和 w 可以将字母大小增加 2pt,从而提高可读性。 l 和 o 被删除,因为它们在当前打印尺寸下很容易与 1、i 和 0 混淆。我们做了一些测试,字符 1、i 和 0 总是被正确读取,l 和 o 有很多错误。省略大写字母的原因与 'm 和 w" 相同。

那么为什么不是序列呢?几个原因: 密钥可以在之后注册,我们不希望任何人猜测序列中的下一个密钥并注册其他人的密钥。外观:我们不需要客户和竞争对手就知道我们只运送了几千把钥匙。

是否有一种实用的方法来生成密钥,确保每个密钥的唯一性并将它们存储在数据库中?谢谢!

【问题讨论】:

  • Gartman 写道:“外观:我们不需要客户和竞争对手就知道我们只运送了几千把钥匙。”根据我的经验,他们弄清楚。
  • 诀窍是获得均匀分布的副本。
  • @starbolin - 你当然可以只生成唯一的密钥,而没有任何重复。
  • @Ramhound 是的,当时我还没有做数学计算,并认为他想重用密钥。我没有意识到他产生的超龄量有多大。其他人已经讨论了这个话题,所以我要退出了。

标签: c# random unique


【解决方案1】:

编辑:@CodeInChaos 指出了一个问题:System.Random 不是很安全,序列可以很容易地复制。我在这里用安全生成器替换了Random

var possibilities = "abcdefghijknpqrstuvxyz0123456789".ToCharArray();
int goal = 1000000;
int codeLength = 8;
var codes = new HashSet<string>();
var random = new RNGCryptoServiceProvider();
while (codes.Count < goal)
{
    var newCode = new char[codeLength];
    for (int i = 0; i < codeLength; i++)
        newCode[i] = possibilities[random.Next(possibilities.Length)];
    codes.Add(new string(newCode));
}
// now write codes to database

static class Extensions
{
    public static byte Next(this RNGCryptoServiceProvider provider, byte maximum)
    {
        var b = new byte[1];
        while (true)
        {
            provider.GetBytes(b);
            if (b[0] < maximum)
                return b[0];
        }
    }
}

(Next 方法不是很快,但对于您的目的可能已经足够)

【讨论】:

  • 这是一个很好的答案,除了一个主要问题。这不保证唯一值。这当然可以很好地生成随机密钥。您可以通过在 for loop 中使用 while loop 来改进代码,条件是生成的字符串在 HashSet 中尚不存在。
  • 实际上,它确实确保了唯一值。 HashSet&lt;string&gt;.Add 在实际添加之前检查该值是否存在于集合中。它返回一个bool,所以你可以知道,但我们真正需要知道的是我们何时达到 1M 键的目标。
  • 每天学习新东西。 =)
  • 感谢您的回答 Tim S。我一定会通过您的解决方案。
  • 您的代码不满足其中一项要求,即“我们不希望任何人猜测序列中的下一个键”。如果攻击者知道算法并观察到单个代码,他可以计算出所有过去和未来使用您的代码生成的代码。
【解决方案2】:

要真正获取随机字符串,可以使用类似这样的代码:

Random rand = new Random(new DateTime().Millisecond);
String[] possibilities = {"a","b","c","d","e","f","g","h","i","j","k",
    "l","n","p","q","r","s","t","u","v","x","y","z","0","1","2","3","4",
    "5","6","7","8","9"};
for (int i = 0; i < 1000000; ++i)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    for (int j = 0; j < 8; ++j)
    {
        sb.Append(possibilities[rand.Next(possibilities.Length)]);
    }
    if (!databaseContains(sb.ToString()))
        databaseAdd(sb.ToString());
    else
        --i;
}

【讨论】:

  • 你可以附加字符,所以你可以写char[] possibilities = "...".ToCharArray()。更容易阅读和写作。
【解决方案3】:

我曾经遇到过类似的问题。我所做的是创建一个唯一的序列 YYYY/MM/DD/HH/MM/SS/millis/nano 并获取其哈希码。之后,我使用哈希作为键。您的客户和您的竞争对手将无法猜测下一个值。这可能不是充分的证据,但对我来说已经足够了!

【讨论】:

  • 这将根据他的要求生成包含“非法”字符的哈希码。此外......这基本上就是Random 类的工作方式。
  • Ramhound,Random 根本不使用哈希。
【解决方案4】:

有没有实用的方法来生成密钥,保证唯一性 将每个键存储在数据库中?

由于这是一个单一的操作,您可以简单地执行以下操作:

1) 生成单个密钥
2) 验证生成的key在数据库中不存在。
3) 如果确实存在,则生成一个新密钥。
3b)如果不存在,则将其写入数据库 4) 返回第 1 步

当然还有其他选择,最终归结为生成一个密钥,并确保它不存在于数据库中。

理论上,您可以生成 1000 万个密钥(以节省处理能力)将它们写入文件。生成密钥后,只需查看每个密钥,看看它是否已经存在于数据库中。 您可能可以编写一个工具,在不到 48 小时内完成这项工作。

【讨论】:

    【解决方案5】:

    如今,100 万并不多,您可以在一台机器上相当快地做到这一点。毕竟是一次性操作。

    1. 获取哈希表(或哈希集)
    2. 生成随机密钥并将它们作为密钥(或直接作为一组)放入其中,直到计数为 100 万
    3. 将它们写入数据库

    我快速而肮脏的测试代码如下所示:

    function new-key {-join'abcdefghijknpqrstuvxyz0123456789'[(0..7|%{random 32})]}
    $keys = @{}
    for(){$keys[(new-key)]=1}
    

    但是 PowerShell 很慢,所以我希望 C++ 或 C# 在这里做得很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-23
      • 2015-07-29
      • 2011-02-17
      相关资源
      最近更新 更多