Chciałbym generować losowe, unikalne ciągi, takie jak te generowane przez bibliotekę MSDN ( na przykład obiekt błędu ). Powinien zostać wygenerowany ciąg typu „t9zk6eay”.
Chciałbym generować losowe, unikalne ciągi, takie jak te generowane przez bibliotekę MSDN ( na przykład obiekt błędu ). Powinien zostać wygenerowany ciąg typu „t9zk6eay”.
Odpowiedzi:
Używanie Guid byłoby całkiem dobrym sposobem, ale aby uzyskać coś podobnego do twojego przykładu, prawdopodobnie chcesz przekonwertować go na ciąg Base64:
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=","");
GuidString = GuidString.Replace("+","");
Pozbywam się „=” i „+”, aby zbliżyć się trochę do twojego przykładu, w przeciwnym razie otrzymasz „==” na końcu ciągu i „+” w środku. Oto przykładowy ciąg wyjściowy:
„OZVV5TpP4U6wJthaCORZEQ”
Convert.ToBase64String
chodzi, zajrzyj tutaj .
new Guid()
bez „hakowania” (manipulowania zegarem lub wewnętrznymi strukturami danych systemu Windows). Możesz swobodnie używać dowolnej liczby rdzeni, wątków, elementów podstawowych synchronizacji itp.
Aktualizacja 2016/1/23
Jeśli uznasz tę odpowiedź za przydatną, możesz być zainteresowany prostą (~ 500 SLOC) biblioteką generowania haseł, którą opublikowałem :
Install-Package MlkPwgen
Następnie możesz wygenerować losowe ciągi, tak jak w odpowiedzi poniżej:
var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
Jedną z zalet biblioteki jest to, że kod jest lepiej rozłożony na czynniki, dzięki czemu można używać bezpiecznej losowości nie tylko do generowania ciągów . Sprawdź na stronie projektu o więcej szczegółów.
Ponieważ nikt jeszcze nie podał bezpiecznego kodu, zamieszczam następujący kod na wypadek, gdyby ktoś uznał go za przydatny.
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();
}
}
Dziękuję Ahmadowi za wskazanie, jak uzyskać kod działający na .NET Core.
.netcore
: Wymień var rng = new RNGCryptoServiceProvider()
zvar rng = RandomNumberGenerator.Create()
Ostrzegam, że identyfikatory GUID nie są liczbami losowymi . Nie powinny być używane jako podstawa do generowania niczego, co według Ciebie będzie całkowicie losowe (patrz http://en.wikipedia.org/wiki/Globally_Unique_Identifier ):
Kryptanaliza generatora GUID WinAPI pokazuje, że skoro sekwencja identyfikatorów GUID V4 jest pseudolosowa, to biorąc pod uwagę stan początkowy, można przewidzieć do 250 000 identyfikatorów GUID zwróconych przez funkcję UuidCreate. Z tego powodu identyfikatory GUID nie powinny być używane w kryptografii, np. Jako klucze losowe.
Zamiast tego po prostu użyj metody C # Random. Coś takiego ( kod znaleziony tutaj ):
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();
}
Identyfikatory GUID są dobre, jeśli chcesz czegoś unikalnego (na przykład unikatowej nazwy pliku lub klucza w bazie danych), ale nie nadają się do czegoś, co chcesz, aby były losowe (jak hasło lub klucz szyfrowania). Więc to zależy od twojej aplikacji.
Edytuj . Microsoft twierdzi, że Random też nie jest taki wspaniały ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ):
Aby wygenerować bezpieczną kryptograficznie liczbę losową odpowiednią do tworzenia losowego hasła, na przykład użyj klasy pochodnej System.Security.Cryptography.RandomNumberGenerator, takiej jak System.Security.Cryptography.RNGCryptoServiceProvider.
Uprościłem rozwiązanie @Michael Kropats i stworzyłem wersję 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();
}
}
Nie sądzę, że są one naprawdę przypadkowe, ale przypuszczam, że to kilka skrótów.
Zawsze, gdy potrzebuję jakiegoś losowego identyfikatora, zwykle używam identyfikatora GUID i konwertuję go na jego „nagą” reprezentację:
Guid.NewGuid().ToString("n");
Dziwię się, dlaczego nie ma rozwiązania CrytpoGraphic. Identyfikator GUID jest unikalny, ale nie jest bezpieczny kryptograficznie . Zobacz to 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);
W przypadku, gdy chcesz dołączyć na początku Guid:
var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);
Czystszy ciąg alfanumeryczny:
result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);
Rozwiązanie Michaela Kropatsa w 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
O to pytano w różnych językach. Oto jedno pytanie dotyczące haseł, które również powinny mieć zastosowanie.
Jeśli chcesz użyć ciągów do skracania adresów URL, będziesz również potrzebować Dictionary <> lub sprawdzenia bazy danych, aby zobaczyć, czy wygenerowany identyfikator nie został już użyty.
Jeśli potrzebujesz ciągów alfanumerycznych z małymi i dużymi literami ([a-zA-Z0-9]), możesz użyć Convert.ToBase64String (), aby uzyskać szybkie i proste rozwiązanie.
Jeśli chodzi o unikalność, sprawdź problem z datą urodzenia, aby obliczyć prawdopodobieństwo kolizji (A) długość wygenerowanych ciągów i (B) liczba wygenerowanych ciągów.
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)
Uzyskaj unikalny klucz za pomocą kodu skrótu GUID
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);
}
string randoms = Guid.NewGuid().ToString().Replace("-", string.Empty).Replace("+", string.Empty).Substring(0, 4);
więcej można znaleźć tutaj