Eu gostaria de gerar cadeias de caracteres únicas aleatórias como as geradas pela biblioteca MSDN. ( Objeto de erro ), por exemplo. Uma string como 't9zk6eay' deve ser gerada.
Eu gostaria de gerar cadeias de caracteres únicas aleatórias como as geradas pela biblioteca MSDN. ( Objeto de erro ), por exemplo. Uma string como 't9zk6eay' deve ser gerada.
Respostas:
Usar Guid seria uma maneira muito boa, mas para obter algo parecido com seu exemplo, você provavelmente deseja convertê-lo em uma string Base64:
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=","");
GuidString = GuidString.Replace("+","");
Eu me livrei de "=" e "+" para chegar um pouco mais perto do seu exemplo, caso contrário, você obterá "==" no final da sua string e um "+" no meio. Aqui está um exemplo de string de saída:
"OZVV5TpP4U6wJthaCORZEQ"
Convert.ToBase64String
se trata, dê uma olhada aqui .
new Guid()
sem "hackear" (adulterar o relógio ou estruturas de dados internas do Windows). Sinta-se à vontade para usar quantos núcleos, threads, primitivos de sincronização, etc., você quiser.
Atualização 2016/1/23
Se você achar esta resposta útil, pode estar interessado em uma biblioteca simples de geração de senha (~ 500 SLOC) que publiquei :
Install-Package MlkPwgen
Então, você pode gerar strings aleatórias, como na resposta abaixo:
var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
Uma vantagem da biblioteca é que o código é melhor fatorado para que você possa usar a aleatoriedade segura para mais do que gerar strings . Confira o site do projeto para mais detalhes.
Já que ninguém forneceu um código seguro ainda, eu posto o seguinte caso alguém o considere útil.
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();
}
}
Obrigado a Ahmad por apontar como fazer o código funcionar no .NET Core.
.netcore
: substituir var rng = new RNGCryptoServiceProvider()
porvar rng = RandomNumberGenerator.Create()
Devo advertir que os GUIDs não são números aleatórios . Eles não devem ser usados como base para gerar algo que você espera que seja totalmente aleatório (consulte http://en.wikipedia.org/wiki/Globally_Unique_Identifier ):
A criptoanálise do gerador WinAPI GUID mostra que, como a sequência de V4 GUIDs é pseudo-aleatória, dado o estado inicial, pode-se prever até os próximos 250.000 GUIDs retornados pela função UuidCreate. É por isso que os GUIDs não devem ser usados em criptografia, por exemplo, como chaves aleatórias.
Em vez disso, apenas use o método C # Random. Algo assim ( código encontrado aqui ):
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 são adequados se você deseja algo exclusivo (como um nome de arquivo ou chave exclusiva em um banco de dados), mas não são adequados para algo que você deseja que seja aleatório (como uma senha ou chave de criptografia). Portanto, depende da sua aplicação.
Editar . A Microsoft diz que Random também não é tão bom ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ):
Para gerar um número aleatório criptograficamente seguro adequado para criar uma senha aleatória, por exemplo, use uma classe derivada de System.Security.Cryptography.RandomNumberGenerator, como System.Security.Cryptography.RNGCryptoServiceProvider.
Simplifiquei a solução @Michael Kropats e fiz uma versão no estilo LINQ.
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();
}
}
Não acho que sejam realmente aleatórios, mas acho que são alguns hashes.
Sempre que preciso de algum identificador aleatório, costumo usar um GUID e convertê-lo em sua representação "simples":
Guid.NewGuid().ToString("n");
Estou surpreso por não haver uma solução criptográfica em vigor. O GUID é exclusivo, mas não criptograficamente seguro . Veja este 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);
Caso você queira adicionar um Guid ao início:
var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);
Uma string alfanumérica mais limpa:
result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);
Solução Michael Kropats em 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
Isso foi solicitado em vários idiomas. Aqui está uma pergunta sobre senhas que deve ser aplicável aqui também.
Se você quiser usar as strings para encurtamento de URL, também precisará de um Dicionário <> ou verificação de banco de dados para ver se um ID gerado já foi usado.
Se quiser strings alfanuméricas com caracteres minúsculos e maiúsculos ([a-zA-Z0-9]), você pode usar Convert.ToBase64String () para uma solução rápida e simples.
Quanto à exclusividade, verifique o problema do aniversário para calcular a probabilidade de uma colisão receber (A) o comprimento das strings geradas e (B) o número de strings geradas.
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)
Obtenha uma chave única usando o código Hash 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);
mais pode ser encontrado aqui