C#逐步生成唯一的安全随机字符串

C#逐步生成唯一的安全随机字符串,c#,random,unique,C#,Random,Unique,我想随机生成唯一和安全的字符串,我想随着时间的推移这样做。我想为我的使用选择尽可能短的长度(足够大,以便随机尝试很有可能失败)。我也希望这个过程是快速的。使用以下代码并测试其唯一性,重复出现的时间比我预期的要早。我不确定是否有什么问题 注意:使用池生成号码安全吗 p.p.S:我不喜欢在字母表上加“-”和“-”。它值得移除吗 string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; s

我想随机生成唯一和安全的字符串,我想随着时间的推移这样做。我想为我的使用选择尽可能短的长度(足够大,以便随机尝试很有可能失败)。我也希望这个过程是快速的。使用以下代码并测试其唯一性,重复出现的时间比我预期的要早。我不确定是否有什么问题

注意:使用池生成号码安全吗

p.p.S:我不喜欢在字母表上加“-”和“-”。它值得移除吗

string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
string Random(int length,string alphabet)
    {
        StringBuilder result = new StringBuilder();
        using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
        {
            for (int i = 0; i < length; i++)
            {
                byte[] buffer = new byte[sizeof(uint)];
                rng.GetBytes(buffer);
                uint num = BitConverter.ToUInt32(buffer, 0);
                result.Append(alphabet[(int)(num % (uint)alphabet.Length)]);
            }
        }

        return result.ToString();
    }
string Alphabet=“abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyzo123456789-”;
随机字符串(整数长度,字符串字母表)
{
StringBuilder结果=新建StringBuilder();
使用(RNGCryptoServiceProvider rng=new RNGCryptoServiceProvider())
{
for(int i=0;i
通常,在
字母表中,每个字符有6位“信息”(共64个字符)。因此,长度=10的字符串有60位信息。对于after sqrt(2^60),即2^30,应该有0.5的碰撞可能性(50%)。2^30相当大,但如果字符数较低,则冲突将发生得更早

请注意,您的代码中可能存在优化(预先分配StringBuilder的“正确”长度),但存在一个bug:

public const string BaseAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

public static string Random(int length, string alphabet = BaseAlphabet)
{
    StringBuilder result = new StringBuilder(length);
    uint maxValue = (uint)((((ulong)uint.MaxValue) + 1) / (uint)alphabet.Length * (uint)alphabet.Length);

    using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        for (int i = 0; i < length; i++)
        {
            uint num;

            do
            {
                byte[] buffer = new byte[sizeof(uint)];
                rng.GetBytes(buffer);
                num = BitConverter.ToUInt32(buffer, 0);
            }
            while (num >= maxValue);

            result.Append(alphabet[(int)(num % (uint)alphabet.Length)]);
        }
    }

    return result.ToString();
}
public const string BaseAlphabet=“abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz012456789-”;
公共静态字符串随机(整数长度,字符串字母表=基本字母表)
{
StringBuilder结果=新StringBuilder(长度);
uint maxValue=(uint)(((ulong)uint.maxValue)+1)/(uint)alphabet.Length*(uint)alphabet.Length);
使用(RNGCryptoServiceProvider rng=new RNGCryptoServiceProvider())
{
for(int i=0;i=maxValue);
结果。追加(字母[(int)(num%(uint)alphabet.Length)];
}
}
返回result.ToString();
}

在您编写的代码中,某些字符可能比其他字符更可能出现。这是因为if(
uint.MaxValue+1
)(rng生成的整个可能数字范围)不能完全被字母表整除。长度
则字母表末尾的字符比开头的字符可能性小。

可能重复的字符可能有助于对代码进行拼写检查。看一看,代码根本不会运行。
重复出现的时间比我预期的要早。
您预期它们是什么时候出现的?什么时候发生的?这感觉像是XY问题-。你为什么要这样做?“短”和“安全”是两件通常不能很好地结合在一起的事情。任何足够短的东西也可以很容易地被粗暴地强迫和/或预测。更重要的是,你不想让东西因为名字难以猜测而变得安全,你想让它们因为根本无法访问而变得安全。如果您使用16个随机字节,并将它们转换为32个字符的十六进制字符串,然后使用它,您将拥有128位的随机性。这当然足以防止碰撞。在这方面,
Guid.NewGuid()
也是如此,尽管这在加密方面并不安全。