1290 Stimmen

Wie kann ich zufällige alphanumerische Zeichenfolgen erzeugen?

Wie kann ich eine zufällige 8 Zeichen alphanumerische Zeichenfolge in C# generieren?

2 Stimmen

Welcher Rest

8 Stimmen

O s o s

2 Stimmen

Es wäre schön, wenn die Sprachlokalisierung in diese Frage einbezogen würde. Vor allem, wenn Ihre Benutzeroberfläche für Chinesisch oder Bulgarisch geeignet sein soll!

6voto

AAD Punkte 281

Eine andere Möglichkeit wäre, Linq zu verwenden und zufällige Zeichen in einem Stringbuilder zu aggregieren.

var chars = "abcdefghijklmnopqrstuvwxyz123456789".ToArray();
string pw = Enumerable.Range(0, passwordLength)
                      .Aggregate(
                          new StringBuilder(),
                          (sb, n) => sb.Append((chars[random.Next(chars.Length)])),
                          sb => sb.ToString());

6voto

Nach Durchsicht der anderen Antworten und unter Berücksichtigung der Kommentare von CodeInChaos sowie der immer noch voreingenommenen (wenn auch weniger voreingenommenen) Antwort von CodeInChaos, dachte ich, dass eine die ultimative Lösung zum Ausschneiden und Einfügen erforderlich war. Als ich meine Antwort aktualisierte, beschloss ich, aufs Ganze zu gehen.

Für eine aktuelle Version dieses Codes besuchen Sie bitte das neue Hg-Repository auf Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Ich empfehle Ihnen, den Code von zu kopieren und einzufügen: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (stellen Sie sicher, dass Sie auf die Schaltfläche "Raw" klicken, um das Kopieren zu erleichtern, und stellen Sie sicher, dass Sie die neueste Version haben. Ich glaube, dieser Link führt zu einer bestimmten Version des Codes, nicht zur neuesten).

Aktualisierte Notizen:

  1. In Bezug auf einige andere Antworten - Wenn Sie die Länge der Ausgabe kennen, benötigen Sie keinen StringBuilder, und wenn Sie ToCharArray verwenden, erstellt und füllt dies das Array (Sie müssen nicht zuerst ein leeres Array erstellen)
  2. In Bezug auf einige andere Antworten - Sie sollten NextBytes verwenden, anstatt aus Leistungsgründen jeweils nur ein Byte zu erhalten.
  3. Technisch könnten Sie das Byte-Array für schnelleren Zugriff pinnen.. es ist in der Regel wert, wenn Ihr Iteration mehr als 6-8 mal über ein Byte-Array. (Hier nicht getan)
  4. Verwendung von RNGCryptoServiceProvider für beste Zufälligkeit
  5. Verwendung von Zwischenspeicherung eines 1 MB großen Puffers mit Zufallsdaten - Benchmarking zeigt, dass die Zugriffsgeschwindigkeit auf einzelne Bytes im Cache ~1000x schneller ist - 9 ms für 1 MB gegenüber 989 ms für nicht gecachte Daten.
  6. Optimierte Ausleitung der Bias-Zone innerhalb meiner neuen Klasse.

Endlösung der Frage:

static char[] charSet =  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
    char[] rName = new char[Length];
    SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

Aber Sie brauchen meine neue (ungetestete) Klasse:

/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference 
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
    static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
    static int lastPosition = 0;
    static int remaining = 0;

    /// <summary>
    /// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
    /// </summary>
    /// <param name="buffer"></param>
    public static void DirectGetBytes(byte[] buffer)
    {
        using (var r = new RNGCryptoServiceProvider())
        {
            r.GetBytes(buffer);
        }
    }

    /// <summary>
    /// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
    /// </summary>
    /// <param name="buffer"></param>
    public static void GetBytes(byte[] buffer)
    {
        if (buffer.Length > byteCache.Length)
        {
            DirectGetBytes(buffer);
            return;
        }

        lock (byteCache)
        {
            if (buffer.Length > remaining)
            {
                DirectGetBytes(byteCache);
                lastPosition = 0;
                remaining = byteCache.Length;
            }

            Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
            lastPosition += buffer.Length;
            remaining -= buffer.Length;
        }
    }

    /// <summary>
    /// Return a single byte from the cache of random data.
    /// </summary>
    /// <returns></returns>
    public static byte GetByte()
    {
        lock (byteCache)
        {
            return UnsafeGetByte();
        }
    }

    /// <summary>
    /// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
    /// </summary>
    /// <returns></returns>
    static byte UnsafeGetByte()
    {
        if (1 > remaining)
        {
            DirectGetBytes(byteCache);
            lastPosition = 0;
            remaining = byteCache.Length;
        }

        lastPosition++;
        remaining--;
        return byteCache[lastPosition - 1];
    }

    /// <summary>
    /// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    public static void GetBytesWithMax(byte[] buffer, byte max)
    {
        if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
        {
            DirectGetBytes(buffer);

            lock (byteCache)
            {
                UnsafeCheckBytesMax(buffer, max);
            }
        }
        else
        {
            lock (byteCache)
            {
                if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
                    DirectGetBytes(byteCache);

                Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
                lastPosition += buffer.Length;
                remaining -= buffer.Length;

                UnsafeCheckBytesMax(buffer, max);
            }
        }
    }

    /// <summary>
    /// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    static void UnsafeCheckBytesMax(byte[] buffer, byte max)
    {
        for (int i = 0; i < buffer.Length; i++)
        {
            while (buffer[i] >= max)
                buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
        }
    }
}

Für die Geschichte - meine ältere Lösung für diese Antwort, verwendet Random Objekt:

    private static char[] charSet =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();

    static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
    static int byteSize = 256; //Labelling convenience
    static int biasZone = byteSize - (byteSize % charSet.Length);
    static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
    public string GenerateRandomString(int Length) //Configurable output string length
    {
      byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
      char[] rName = new char[Length];
      lock (rGen) //~20-50ns
      {
          rGen.NextBytes(rBytes);

          for (int i = 0; i < Length; i++)
          {
              while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
                  rBytes[i] = rGen.NextByte();
              rName[i] = charSet[rBytes[i] % charSet.Length];
          }
      }
      return new string(rName);
    }

Leistung:

  1. SecureFastRandom - Erster Einzellauf \= ~9-33ms . Nicht wahrnehmbar. Laufend : 5ms (manchmal bis zu 13ms) über 10.000 Iterationen, mit einer einzigen durchschnittlichen Iteration= 1,5 Mikrosekunden. . Hinweis: Erfordert in der Regel 2, gelegentlich aber auch bis zu 8 Cache-Aktualisierungen - je nachdem, wie viele einzelne Bytes die Bias-Zone überschreiten.
  2. Zufällig - Erster Einzellauf \= ~0-1ms . Nicht wahrnehmbar. Laufend : 5ms über 10.000 Iterationen. Mit einer einzigen durchschnittlichen Iteration= .5 Mikrosekunden. . Ungefähr die gleiche Geschwindigkeit.

Schauen Sie auch nach:

Diese Links sind ein weiterer Ansatz. Die Pufferung könnte zu dieser neuen Codebasis hinzugefügt werden, aber am wichtigsten war es, verschiedene Ansätze zur Beseitigung von Verzerrungen zu erforschen und die Geschwindigkeiten und Vor- und Nachteile zu vergleichen.

6voto

Wai Ha Lee Punkte 8153

Frage: Warum sollte ich meine Zeit damit verschwenden Enumerable.Range statt der Eingabe von "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789" ?

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var randomCharacters = GetRandomCharacters(8, true);
        Console.WriteLine(new string(randomCharacters.ToArray()));
    }

    private static List<char> getAvailableRandomCharacters(bool includeLowerCase)
    {
        var integers = Enumerable.Empty<int>();
        integers = integers.Concat(Enumerable.Range('A', 26));
        integers = integers.Concat(Enumerable.Range('0', 10));

        if ( includeLowerCase )
            integers = integers.Concat(Enumerable.Range('a', 26));

        return integers.Select(i => (char)i).ToList();
    }

    public static IEnumerable<char> GetRandomCharacters(int count, bool includeLowerCase)
    {
        var characters = getAvailableRandomCharacters(includeLowerCase);
        var random = new Random();
        var result = Enumerable.Range(0, count)
            .Select(_ => characters[random.Next(characters.Count)]);

        return result;
    }
}

Antwort: Zauberschnüre sind SCHLECHT. Ist Jemandem aufgefallen, dass es keine " I " in meiner Zeichenkette ganz oben? Meine Mutter hat mir beigebracht, aus diesem Grund keine Zauberschnüre zu verwenden...

n.b. 1: Wie viele andere, z.B. @dtb, sagten, verwenden Sie nicht System.Random wenn Sie kryptographische Sicherheit benötigen...

n.b. 2: Diese Antwort ist nicht die effizienteste oder kürzeste, aber ich wollte den Platz, um die Antwort von der Frage zu trennen. Der Zweck meiner Antwort ist eher, vor magischen Zeichenketten zu warnen, als eine ausgefallene innovative Antwort zu geben.

5voto

Misha Zaslavsky Punkte 6203

Eine einfache und hochsichere Möglichkeit wäre die Generierung der Kryptographie Aes Schlüssel.

public static string GenerateRandomString()
{
    using Aes crypto = Aes.Create();
    crypto.GenerateKey();
    return Convert.ToBase64String(crypto.Key);
}

5voto

RouR Punkte 5719

Versuchen Sie, zwei Teile zu kombinieren: eindeutig (Sequenz, Zähler oder Datum) und zufällig

public class RandomStringGenerator
{
    public static string Gen()
    {
        return ConvertToBase(DateTime.UtcNow.ToFileTimeUtc()) + GenRandomStrings(5); //keep length fixed at least of one part
    }

    private static string GenRandomStrings(int strLen)
    {
        var result = string.Empty;

        using (var gen = new RNGCryptoServiceProvider())
        {
            var data = new byte[1];

            while (result.Length < strLen)
            {
                gen.GetNonZeroBytes(data);
                int code = data[0];
                if (code > 48 && code < 57 || // 0-9
                    code > 65 && code < 90 || // A-Z
                    code > 97 && code < 122   // a-z
                )
                {
                    result += Convert.ToChar(code);
                }
            }

            return result;
        }
    }

    private static string ConvertToBase(long num, int nbase = 36)
    {
        const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //if you wish to make the algorithm more secure - change order of letter here

        // check if we can convert to another base
        if (nbase < 2 || nbase > chars.Length)
            return null;

        int r;
        var newNumber = string.Empty;

        // in r we have the offset of the char that was converted to the new base
        while (num >= nbase)
        {
            r = (int)(num % nbase);
            newNumber = chars[r] + newNumber;
            num = num / nbase;
        }
        // the last number to convert
        newNumber = chars[(int)num] + newNumber;

        return newNumber;
    }
}

Tests:

    [Test]
    public void Generator_Should_BeUnigue1()
    {
        //Given
        var loop = Enumerable.Range(0, 1000);
        //When
        var str = loop.Select(x=> RandomStringGenerator.Gen());
        //Then
        var distinct = str.Distinct();
        Assert.AreEqual(loop.Count(),distinct.Count()); // Or Assert.IsTrue(distinct.Count() < 0.95 * loop.Count())
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X