独特的随机字符串生成

Kir*_*tan 91 c# random

我想生成随机唯一字符串,如MSDN库生成的字符串:

例如,http://msdn.microsoft.com/en-us/library/t9zk6eay.aspx.应生成类似't9zk6eay'的字符串.

Mic*_*pat 171

更新2016/1/23

如果您觉得这个答案有用,您可能会对我发布的简单(~500 SLOC)密码生成库感兴趣:

Install-Package MlkPwgen
Run Code Online (Sandbox Code Playgroud)

然后你就可以像下面的答案一样生成随机字符串:

var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
Run Code Online (Sandbox Code Playgroud)

该库的一个优点是代码更好地被排除,因此您可以使用安全随机性而不是生成字符串.查看项目网站了解更多详情.

原始答案

由于还没有人提供安全代码,我发布以下内容以防任何人发现它有用.

string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
    if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
    if (string.IsNullOrEmpty(allowedChars)) throw new ArgumentException("allowedChars may not be empty.");

    const int byteSize = 0x100;
    var allowedCharSet = new HashSet<char>(allowedChars).ToArray();
    if (byteSize < allowedCharSet.Length) throw new ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize));

    // Guid.NewGuid and System.Random are not particularly random. By using a
    // cryptographically-secure random number generator, the caller is always
    // protected, regardless of use.
    using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create()) {
        var result = new StringBuilder();
        var buf = new byte[128];
        while (result.Length < length) {
            rng.GetBytes(buf);
            for (var i = 0; i < buf.Length && result.Length < length; ++i) {
                // Divide the byte into allowedCharSet-sized groups. If the
                // random value falls into the last group and the last group is
                // too small to choose from the entire allowedCharSet, ignore
                // the value in order to avoid biasing the result.
                var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);
                if (outOfRangeStart <= buf[i]) continue;
                result.Append(allowedCharSet[buf[i] % allowedCharSet.Length]);
            }
        }
        return result.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

感谢Ahmad指出如何使代码在.NET Core上运行.

  • 实际上安全有用; 提前致谢 (7认同)
  • 谁的目标是`.netcore`:用`var rng = RandomNumberGenerator.Create()替换`var rng = new RNGCryptoServiceProvider()` (4认同)
  • @LeeGrissom,偏见是一个重要方面.让我们假设您的字母表包含255个字符,并且您获得0到255之间的随机值.在环形缓冲区中,值0和255都将对应于相同的字符,该字符会使结果倾斜以支持字母表中的第一个字符,它将更不随机.如果这很重要取决于课程的应用. (2认同)
  • 为什么要计算 'var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);' 对于每次迭代?您可以在“使用”之前计算它。 (2认同)

Mar*_*iec 75

使用Guid会是一个非常好的方法,但是为了获得类似于您的示例的内容,您可能希望将其转换为Base64字符串:

    Guid g = Guid.NewGuid();
    string GuidString = Convert.ToBase64String(g.ToByteArray());
    GuidString = GuidString.Replace("=","");
    GuidString = GuidString.Replace("+","");
Run Code Online (Sandbox Code Playgroud)

我摆脱了"="和"+"以更接近你的例子,否则你在字符串的末尾得到"=="而在中间得到"+".这是一个示例输出字符串:

"OZVV5TpP4U6wJthaCORZEQ"

  • Guid不应被视为安全随机字符串,因为可以猜测序列.Guid旨在避免关键冲突,而不是随机冲突.堆栈溢出有一些很好的[关于Guid随机性的讨论](http://stackoverflow.com/a/290463/366550). (18认同)
  • 您应该考虑更换/. (15认同)
  • @SimonEjsing如果你真的可以编写一个在使用`new Guid()`而不是"黑客"(篡改时钟或内部Windows数据结构)时发生冲突的应用程序,我会邀请你喝啤酒.您可以根据需要随意使用尽可能多的内核,线程,同步原语等. (4认同)
  • 可以将guid转换为base64并替换+和=增加碰撞概率吗? (2认同)

Kel*_*tex 38

我会提醒GUID 不是随机数.它们不应被用作生成您期望完全随机的任何内容的基础(请参阅http://en.wikipedia.org/wiki/Globally_Unique_Identifier):

WinAPI GUID生成器的密码分析表明,由于V4 GUID的序列是伪随机的,因此在给定初始状态的情况下,可以预测由函数UuidCreate返回的下一个250,000个GUID.这就是GUID不应该用于密码学的原因,例如,作为随机密钥.

相反,只需使用C#Random方法.像这样的东西(这里的代码):

private string RandomString(int size)
{
  StringBuilder builder = new StringBuilder();
  Random random = new Random();
  char ch ;
  for(int i=0; i<size; i++)
  {
    ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
    builder.Append(ch);
  }
  return builder.ToString();
}
Run Code Online (Sandbox Code Playgroud)

如果你想要一些独特的东西(比如数据库中的唯一文件名或密钥),GUID就可以了,但它们不适合你想要随机的东西(比如密码或加密密钥).所以这取决于你的应用程序.

编辑.微软称Random也不是那么好(http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx):

例如,要生成适用于创建随机密码的加密安全随机数,请使用从System.Security.Cryptography.RandomNumberGenerator派生的类,例如System.Security.Cryptography.RNGCryptoServiceProvider.

  • C#随机类也不是"随机"的,并且不适用于任何加密代码,因为它是从特定种子编号开始的经典随机生成器.同一种子也会返回相同的数字序列; 这里的GUID方法已经好多了(不是"随机"而是"独特"). (5认同)
  • @Lucero:你说的没错.Microsoft建议,"要生成适合创建随机密码的加密安全随机数,例如,请使用从System.Security.Cryptography.RandomNumberGenerator派生的类,例如System.Security.Cryptography.RNGCryptoServiceProvider." (3认同)

Osk*_*erg 13

我简化了@Michael Kropats解决方案并制作了LINQ-esque版本.

string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
{       
    var outOfRange = byte.MaxValue + 1 - (byte.MaxValue + 1) % alphabet.Length;

    return string.Concat(
        Enumerable
            .Repeat(0, int.MaxValue)
            .Select(e => RandomByte())
            .Where(randomByte => randomByte < outOfRange)
            .Take(length)
            .Select(randomByte => alphabet[randomByte % alphabet.Length])
    );
}

byte RandomByte()
{
    using (var randomizationProvider = new RNGCryptoServiceProvider())
    {
        var randomBytes = new byte[1];
        randomizationProvider.GetBytes(randomBytes);
        return randomBytes.Single();
    }   
}
Run Code Online (Sandbox Code Playgroud)


Luc*_*ero 11

我不认为他们真的是随机的,但我的猜测是那些是哈希.

每当我需要一些随机标识符时,我通常会使用GUID并将其转换为"裸"表示:

Guid.NewGuid().ToString("n");
Run Code Online (Sandbox Code Playgroud)


Dev*_*evC 5

尝试结合使用 Guid 和 Time.Ticks

 var randomNumber = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + DateTime.Now.Ticks;
     randomNumber = System.Text.RegularExpressions.Regex.Replace(randomNumber, "[^0-9a-zA-Z]+", "");
Run Code Online (Sandbox Code Playgroud)