独特的随机字符串生成

时间:2009-04-08 14:27:34

标签: c# random

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

例如,

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

14 个答案:

答案 0 :(得分:165)

更新2016/1/23

如果您觉得此答案有用,您可能会对a simple (~500 SLOC) password generation library I published

感兴趣
Install-Package MlkPwgen

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

var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);

该库的一个优点是代码更好地被排除,因此您可以使用安全随机性for more than generating strings。查看the project site了解详情。

原始答案

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

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();
    }
}

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

答案 1 :(得分:70)

使用Guid会是一个非常好的方法,但是为了获得看起来像你的例子,你可能想要将它转换为Base64字符串:

    Guid g = Guid.NewGuid();
    string GuidString = Convert.ToBase64String(g.ToByteArray());
    GuidString = GuidString.Replace("=","");
    GuidString = GuidString.Replace("+","");

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

“OZVV5TpP4U6wJthaCORZEQ”

答案 2 :(得分:37)

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

  

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

相反,只需使用C#Random方法即可。这样的事情(code found here):

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();
}

如果您需要唯一(如数据库中的唯一文件名或密钥),GUID就可以了,但它们不适合您希望随机(像密码或加密密钥)。所以这取决于你的申请。

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

  

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

答案 3 :(得分:12)

我简化了@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();
    }   
}

答案 4 :(得分:11)

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

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

Guid.NewGuid().ToString("n");

答案 5 :(得分:3)

尝试在Guid和Time.Ticks

之间进行组合
 var randomNumber = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + DateTime.Now.Ticks;
     randomNumber = System.Text.RegularExpressions.Regex.Replace(randomNumber, "[^0-9a-zA-Z]+", "");

答案 6 :(得分:1)

在VB.net中使用Michael Kropats解决方案

Private Function RandomString(ByVal length As Integer, Optional ByVal allowedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") As String
    If length < 0 Then Throw New ArgumentOutOfRangeException("length", "length cannot be less than zero.")
    If String.IsNullOrEmpty(allowedChars) Then Throw New ArgumentException("allowedChars may not be empty.")


    Dim byteSize As Integer = 256
    Dim hash As HashSet(Of Char) = New HashSet(Of Char)(allowedChars)
    'Dim hash As HashSet(Of String) = New HashSet(Of String)(allowedChars)
    Dim allowedCharSet() = hash.ToArray

    If byteSize < allowedCharSet.Length Then 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.
    Dim rng = New System.Security.Cryptography.RNGCryptoServiceProvider()
    Dim result = New System.Text.StringBuilder()
    Dim buf = New Byte(128) {}
    While result.Length < length
        rng.GetBytes(buf)
        Dim i
        For i = 0 To buf.Length - 1 Step +1
            If result.Length >= length Then Exit For
            ' 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.
            Dim outOfRangeStart = byteSize - (byteSize Mod allowedCharSet.Length)
            If outOfRangeStart <= buf(i) Then
                Continue For
            End If
            result.Append(allowedCharSet(buf(i) Mod allowedCharSet.Length))
        Next
    End While
    Return result.ToString()
End Function

答案 7 :(得分:1)

令我惊讶的是为什么没有适当的CrytpoGraphic解决方案。 GUID是唯一的,但不是加密安全的 See this Dotnet Fiddle.

var bytes = new byte[40]; // byte size
using (var crypto = new RNGCryptoServiceProvider())
  crypto.GetBytes(bytes);

var base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);

如果您想添加Guid:

var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);

更清晰的字母数字字符串:

result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);

答案 8 :(得分:0)

这已被要求提供各种语言。这里的one question about passwords也适用于此。

如果您想使用字符串进行网址缩短,您还需要一个字典&lt;&gt;或数据库检查以查看是否已使用生成的ID。

答案 9 :(得分:0)

如果您想要一个带小写大写字符([a-zA-Z0-9])的字母数字字符串,您可以使用Convert.ToBase64String()来获得快速简单的解决方案。

至于唯一性,请查看birthday problem以计算发生碰撞的可能性(A)生成的字符串长度和(B)生成的字符串数。

Random random = new Random();

int outputLength = 10;
int byteLength = (int)Math.Ceiling(3f / 4f * outputLength); // Base64 uses 4 characters for every 3 bytes of data; so in random bytes we need only 3/4 of the desired length
byte[] randomBytes = new byte[byteLength];
string output;
do
{
    random.NextBytes(randomBytes); // Fill bytes with random data
    output = Convert.ToBase64String(randomBytes); // Convert to base64
    output = output.Substring(0, outputLength); // Truncate any superfluous characters and/or padding
} while (output.Contains('/') || output.Contains('+')); // Repeat if we contain non-alphanumeric characters (~25% chance if length=10; ~50% chance if length=20; ~35% chance if length=32)

答案 10 :(得分:0)

这对我来说非常适合

    private string GeneratePasswordResetToken()
    {
        string token = Guid.NewGuid().ToString();
        var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(token);
        return Convert.ToBase64String(plainTextBytes);
    }

答案 11 :(得分:-1)

  • 不确定Microsoft的链接是否是随机生成的
  • 看看新的Guid()。ToString()

答案 12 :(得分:-1)

Get Unique Key using GUID Hash code

public static string GetUniqueKey(int length)
{
    string guidResult = string.Empty;

    while (guidResult.Length < length)
    {
        // Get the GUID.
        guidResult += Guid.NewGuid().ToString().GetHashCode().ToString("x");
    }

    // Make sure length is valid.
    if (length <= 0 || length > guidResult.Length)
        throw new ArgumentException("Length must be between 1 and " + guidResult.Length);

    // Return the first length bytes.
    return guidResult.Substring(0, length);
}

答案 13 :(得分:-2)

我在Windows上针对Linux命令的一站式解决方案是scoop。 从scoop.sh

安装瓢
scoop install openssl
openssl rand -base64 32
Dca3c3pptVkcb8fx243wN/3f/rQxx/rWYL8y7rZrGrA=