webentwicklung-frage-antwort-db.com.de

Einzigartige zufällige String-Generierung

Ich möchte zufällige eindeutige Zeichenfolgen wie die von der MSDN-Bibliothek generierten generieren:

http://msdn.Microsoft.com/en-us/library/t9zk6eay.aspx zum Beispiel. Ein String wie 't9zk6eay' sollte generiert werden.

86
Kirtan

Die Verwendung von Guid wäre ein ziemlich guter Weg, aber um etwas wie Ihr Beispiel aussehen zu lassen, möchten Sie es wahrscheinlich in eine Base64-Zeichenfolge konvertieren:

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

Ich werde "=" und "+" los, um Ihrem Beispiel etwas näher zu kommen. Andernfalls erhalten Sie "==" am Ende Ihrer Zeichenfolge und ein "+" in der Mitte. Hier ist ein Beispiel einer Ausgabezeichenfolge:

"OZVV5TpP4U6wJthaCORZEQ"

68
Mark Synowiec

Update 23.01.2016

Wenn Sie diese Antwort als nützlich erachten, interessieren Sie sich vielleicht für eine einfache (ca. 500 SLOC) -Kennwortbibliothek, die ich veröffentlicht habe :

Install-Package MlkPwgen

Dann können Sie zufällige Zeichenfolgen wie in der Antwort unten erzeugen:

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

Ein Vorteil der Bibliothek ist, dass der Code besser herausgefiltert wird, sodass Sie die sichere Zufallsauswahl für mehr als das Erzeugen von Strings verwenden können. Überprüfen Sie die Projekt-Site für weitere Details.

Ursprüngliche Antwort

Da bisher noch kein Sicherheitscode bereitgestellt wurde, poste ich Folgendes, falls es für jemanden nützlich ist.

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

Vielen Dank an Ahmad für den Hinweis, wie der Code in .NET Core funktioniert.

165
Michael Kropat

Ich möchte darauf hinweisen, dass GUIDs keine Zufallszahlen sind. Sie sollten nicht als Grundlage für die Generierung von Elementen verwendet werden, von denen Sie erwarten, dass sie völlig zufällig sind (siehe http://en.wikipedia.org/wiki/Globally_Unique_Identifier ):

Die Kryptanalyse des WinAPI-Generators GUID zeigt, dass, da die Reihenfolge der V4-GUIDs pseudo-zufällig ist, angesichts des Anfangsstatus bis zu 250.000 GUIDs vorhergesagt werden können, die von der Funktion UuidCreate zurückgegeben werden. Aus diesem Grund sollten GUIDs nicht in der Kryptographie verwendet werden, z. als zufällige Schlüssel.

Verwenden Sie stattdessen einfach die C # Random-Methode. So etwas ( Code hier ):

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

GUIDs sind in Ordnung, wenn Sie etwas unique wünschen (wie einen eindeutigen Dateinamen oder einen eindeutigen Schlüssel in einer Datenbank), aber sie eignen sich nicht für etwas, das Sie random (wie ein Kennwort oder einen Verschlüsselungsschlüssel) haben möchten. Es hängt also von Ihrer Anwendung ab.

Bearbeiten. Microsoft sagt, dass Random nicht so toll ist ( http://msdn.Microsoft.com/en-us/library/system.random(VS.71).aspx ):

Verwenden Sie zum Generieren einer kryptografisch sicheren Zufallszahl, die zum Erstellen eines Zufallskennworts geeignet ist, eine von System.Security.Cryptography.RandomNumberGenerator abgeleitete Klasse, z. B. System.Security.Cryptography.RNGCryptoServiceProvider.

37
Keltex

Ich glaube nicht, dass sie wirklich zufällig sind, aber ich schätze, das sind ein paar Hashes.

Wann immer ich eine zufällige Kennung benötige, verwende ich normalerweise eine GUID und konvertiere sie in ihre "nackte" Darstellung:

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

Ich habe die Lösung von @Michael Kropats vereinfacht und eine LINQ-artige Version erstellt.

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();
    }   
}
11
Oskar Sjöberg

Probiere die Kombination zwischen Guid und Time.Ticks

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

Michael Kropats Lösung in VB.net

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
1
jhersey29

Ich bin überrascht, warum es keine CrytpoGraphic-Lösung gibt. GUID ist eindeutig, aber nicht kryptographisch sicher. Siehe diese Dotnet-Geige.

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

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

Falls Sie mit einer Guid vorbereiten möchten:

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

Eine saubere alphanumerische Zeichenfolge:

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

Wenn Sie alphanumerische Zeichenfolgen mit den Großbuchstaben und ([a-zA-Z0-9]) verwenden möchten, können Sie Convert.ToBase64String () für eine schnelle und einfache Lösung verwenden.

Im Hinblick auf die Eindeutigkeit prüfen Sie das Problem mit dem Problem birthday , um zu berechnen, wie wahrscheinlich eine Kollision ist (A) die Länge der generierten Zeichenfolgen und (B) die Anzahl der erzeugten Zeichenfolgen.

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)
0
Timo

Das funktioniert perfekt für mich 

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

Dies wurde nach verschiedenen Sprachen gefragt. Hier ist eine Frage zu Passwörtern die auch hier gelten sollte. 

Wenn Sie die Zeichenfolgen zur URL-Verkürzung verwenden möchten, benötigen Sie außerdem ein Dictionary <> oder eine Datenbankprüfung, um festzustellen, ob bereits eine generierte ID verwendet wurde. 

0
Pontus Gagge