Observe que você NÃO deve usar nenhum método baseado na Randomclasse para gerar senhas. A semeadura Randomtem entropia muito baixa, portanto não é realmente seguro. Use um PRNG criptográfico para senhas.
CodesInChaos
2
Seria bom incluir a localização de idiomas nesta pergunta. Especialmente se o seu gui precisar atender chinês ou búlgaro!
Peter Jamsmenson
15
Algo com tantos votos positivos e tantas respostas de qualidade não merece ser marcado como fechado. Eu voto para que seja reaberto.
John Coleman
Respostas:
1686
Ouvi dizer que o LINQ é o novo preto, então aqui está minha tentativa de usar o LINQ:
privatestaticRandom random =newRandom();publicstaticstringRandomString(int length){conststring chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";returnnewstring(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
(Observação: o uso da Randomclasse torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use a RNGCryptoServiceProviderclasse se precisar de um gerador de números aleatórios forte.)
@ Alex: Eu executei alguns testes rápidos e parece ter uma escala linear ao gerar strings mais longas (desde que haja realmente memória suficiente disponível). Dito isto, a resposta de Dan Rigby foi quase duas vezes mais rápida que essa em todos os testes.
LukeH
6
Bem. Se o seu critério é que ele use linq e tenha uma péssima narrativa de código, então é definitivamente o joelho da abelha. Tanto a narrativa do código quanto o caminho real da execução são ineficientes e indiretos. Não me interpretem mal, eu sou um grande hipster de código (eu amo python), mas isso é praticamente uma máquina rube goldberg.
precisa saber é o seguinte
5
Embora isso tecnicamente responda à pergunta, sua saída é muito enganadora. Gerando 8 sons caracteres aleatórios como não pode haver muito muitos resultados, que esta na melhor das hipóteses produz 2 bilhões de resultados diferentes. E na prática ainda menos. Você também deve adicionar um aviso BIG FAT para não usá-lo para nada relacionado à segurança.
CodesInChaos
41
@xaisoft: as letras minúsculas são deixadas como exercício para o leitor.
dtb
15
A linha a seguir é mais eficiente em termos de memória (e, portanto, em tempo) do que a dadareturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams
376
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";var stringChars =newchar[8];var random =newRandom();for(int i =0; i < stringChars.Length; i++){
stringChars[i]= chars[random.Next(chars.Length)];}var finalString =newString(stringChars);
Não é tão elegante quanto a solução Linq.
(Observação: o uso da Randomclasse torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use a RNGCryptoServiceProviderclasse se precisar de um gerador de números aleatórios forte.)
@ Alex: Esta não é a resposta mais rápida absoluta, mas é a resposta "real" mais rápida (ou seja, daquelas que permitem o controle sobre os caracteres usados e o comprimento da string).
LukeH
2
@Alex: A GetRandomFileNamesolução de Adam Porad é mais rápida, mas não permite nenhum controle dos caracteres utilizados e o tamanho máximo possível é de 11 caracteres. A Guidsolução de Douglas é extremamente rápida, mas os caracteres são restritos a A-F0-9 e o comprimento máximo possível é de 32 caracteres.
LukeH
1
@ Adam: Sim, você pode concordar com o resultado de várias chamadas, GetRandomFileNamemas (a) perderia sua vantagem de desempenho e (b) seu código se tornaria mais complicado.
LukeH
2
@xaisoft crie sua instância do objeto Random () fora do seu loop. Se você criar várias instâncias de Random () em um curto intervalo, a chamada para .Next () retornará o mesmo valor que Random () usará uma semente baseada em tempo.
Dan Rigby
2
@xaisoft Não use esta resposta para nada crítico de segurança, como senhas. System.Randomnão é adequado para segurança.
CodesInChaos
333
ATUALIZADO com base nos comentários. A implementação original gerou ah ~ 1,95% do tempo e os caracteres restantes ~ 1,56% do tempo. A atualização gera todos os caracteres ~ 1,61% do tempo.
O .NET Core 3 (e futuras plataformas que oferecem suporte ao .NET Standard 2.1 ou superior) fornece um método criptograficamente sólido RandomNumberGenerator.GetInt32 () para gerar um número inteiro aleatório dentro de um intervalo desejado.
Ao contrário de algumas das alternativas apresentadas, essa é criptograficamente sólida .
using System;
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey{publicclassKeyGenerator{internalstaticreadonlychar[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();publicstaticstringGetUniqueKey(int size){byte[] data =newbyte[4*size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);for(int i =0; i < size; i++){var rnd =BitConverter.ToUInt32(data, i *4);var idx = rnd % chars.Length;
result.Append(chars[idx]);}return result.ToString();}publicstaticstringGetUniqueKeyOriginal_BIASED(int size){char[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();byte[] data =newbyte[size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);foreach(byte b in data){
result.Append(chars[b %(chars.Length)]);}return result.ToString();}}}
Baseado em uma discussão de alternativas aqui e atualizado / modificado com base nos comentários abaixo.
Aqui está um pequeno equipamento de teste que demonstra a distribuição de caracteres na saída antiga e atualizada. Para uma discussão profunda da análise da aleatoriedade , consulte random.org.
using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;
namespace CryptoRNGDemo{classProgram{constint REPETITIONS =1000000;constint KEY_SIZE =32;staticvoidMain(string[] args){Console.WriteLine("Original BIASED implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKeyOriginal_BIASED);Console.WriteLine("Updated implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKey);Console.ReadKey();}staticvoidPerformTest(int repetitions,int keySize,Func<int,string> generator){Dictionary<char,int> counts =newDictionary<char,int>();foreach(var ch inUniqueKey.KeyGenerator.chars) counts.Add(ch,0);for(int i =0; i < REPETITIONS; i++){var key = generator(KEY_SIZE);foreach(var ch in key) counts[ch]++;}int totalChars = counts.Values.Sum();foreach(var ch inUniqueKey.KeyGenerator.chars){Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");}}}}
Isso parece a abordagem correta para mim - senhas aleatórias, sais, entropia e assim por diante não devem ser geradas usando Random (), que é otimizado para velocidade e gera seqüências reproduzíveis de números; Por outro lado, RNGCryptoServiceProvider.GetNonZeroBytes () produz seqüências curtas de números que NÃO são reproduzíveis.
mindplay.dk
25
As letras são ligeiramente tendenciosas (255% 62! = 0). Apesar dessa pequena falha, é de longe a melhor solução aqui.
CodesInChaos
13
Observe que isso não é válido se você deseja aleatoriedade imparcial e com força de criptografia. (E se você não quer isso, então por que o uso RNGCSPem primeiro lugar?) Usando mod para indexar nos charsmeios de matriz que você vai ser tendenciosa saída a menos que chars.Lengthpassa a ser um divisor de 256.
LukeH
15
Uma possibilidade de reduzir muito o viés é solicitar 4*maxSizebytes aleatórios e usar (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Eu também usaria em GetBytesvez de GetNonZeroBytes. E, finalmente, você pode remover a primeira chamada para GetNonZeroBytes. Você não está usando o resultado.
CodesInChaos
14
Curiosidade: AZ az 0-9 tem 62 caracteres. As pessoas estão apontando o viés da letra porque 256% 62! = 0. Os IDs de vídeo do YouTube são AZ az 0-9, além de "-" e "_", que produz 64 caracteres possíveis, divididos em 256 uniformemente. Coincidência? Eu acho que não! :)
qJake
200
Solução 1 - maior 'faixa' com comprimento mais flexível
Esta solução tem mais alcance do que usar um GUID porque um GUID possui alguns bits fixos que são sempre os mesmos e, portanto, não aleatórios, por exemplo, o caractere 13 em hexadecimal é sempre "4" - pelo menos em um GUID da versão 6.
Essa solução também permite gerar uma sequência de qualquer tamanho.
Solução 2 - Uma linha de código - válida para até 22 caracteres
Você não pode gerar cadeias de caracteres desde que a Solução 1 e a cadeia de caracteres não tenham o mesmo intervalo devido a bits fixos nos GUIDs, mas em muitos casos isso fará o trabalho.
Solução 3 - um pouco menos de código
Guid.NewGuid().ToString("n").Substring(0,8);
Principalmente mantendo isso aqui para fins históricos. Ele usa um pouco menos de código, que, apesar de custar menos, tem um alcance - porque usa hex em vez de base64, são necessários mais caracteres para representar o mesmo intervalo em comparação com as outras soluções.
O que significa mais chances de colisão - testá-lo com 100.000 iterações de 8 cadeias de caracteres gerou uma duplicata.
Você realmente gerou uma duplicata? Surpreendente em 5.316.911.983.139.663.491.615.228.241.121.400.000 combinações possíveis de GUIDs.
Alex
73
@Alex: ele está encurtando o GUID para 8 caracteres, então a probabilidade de colisões é muito maior do que a dos GUIDs.
dtb 28/08/09
23
Ninguém pode apreciar isso além de nerds :) Sim, você está absolutamente certo, o limite de 8 caracteres faz a diferença.
2828 Alex
31
Guid.NewGuid (). ToString ("n") manterá os traços afastados, não é necessária a chamada Replace (). Mas deve ser mencionado, os GUIDs são apenas 0-9 e AF. O número de combinações é "bom o suficiente", mas nem de perto o que uma verdadeira seqüência aleatória alfanumérica permite. As chances de colisão são de 1: 4.294.967.296 - o mesmo que um número inteiro aleatório de 32 bits.
richardtallent 28/08/09
32
1) Os GUIDs são projetados para serem exclusivos, não aleatórios. Embora as versões atuais do Windows gerem GUIDs V4 realmente aleatórios, isso não é garantido. Por exemplo, versões mais antigas do Windows usavam GUIDs V1, onde o seu poderia falhar. 2) O simples uso de caracteres hexadecimais reduz significativamente a qualidade da sequência aleatória. De 47 a 32 bits. 3) As pessoas estão subestimando a probabilidade de colisão, uma vez que a dão para pares individuais. Se você gerar 100k valores de 32 bits, provavelmente terá uma colisão entre eles. Consulte Problema de aniversário.
CodesInChaos
72
Aqui está um exemplo que eu roubei do exemplo de Sam Allen no Dot Net Perls
Se você precisar apenas de 8 caracteres, use Path.GetRandomFileName () no espaço para nome System.IO. Sam diz que o uso do método "Path.GetRandomFileName aqui às vezes é superior, porque usa RNGCryptoServiceProvider para obter melhor aleatoriedade. No entanto, é limitado a 11 caracteres aleatórios".
GetRandomFileName sempre retorna uma cadeia de 12 caracteres com um ponto no nono caractere. Portanto, você precisará retirar o período (já que isso não é aleatório) e, em seguida, pegar 8 caracteres da sequência. Na verdade, você pode apenas pegar os 8 primeiros caracteres e não se preocupar com o período.
Isso funciona bem. Eu o executei através de 100.000 iterações e nunca tive um nome duplicado. No entanto, eu queria encontrar várias palavras vulgares (em Inglês). Nem pensaria nisso, exceto que um dos primeiros da lista tinha F *** nele. Apenas um alerta se você usar isso para algo que o usuário verá.
Techturtle 9/10/12
3
@techturtle Obrigado pelo aviso. Suponho que exista o risco de palavras vulgares com qualquer geração aleatória de strings que use todas as letras do alfabeto.
Adam Porad 10/10/12
agradável e simples, mas não é bom para longa seqüência ... voto para este bom truque
Maher Abuthraa
Esse método parece retornar apenas seqüências alfanuméricas em minúsculas.
Jaybro #
2
De vez em quando, há palavras vulgares, mas se você continuar assim por algum tempo, escreverá Shakespeare. (Apenas algumas vidas do universo :).
Slothario
38
Os principais objetivos do meu código são:
A distribuição das strings é quase uniforme (não se preocupe com pequenos desvios, desde que sejam pequenos)
Ele gera mais de alguns bilhões de strings para cada conjunto de argumentos. Gerar uma seqüência de 8 caracteres (~ 47 bits de entropia) não faz sentido se o seu PRNG gerar apenas 2 bilhões (31 bits de entropia) de valores diferentes.
É seguro, pois espero que as pessoas usem isso para senhas ou outros tokens de segurança.
A primeira propriedade é obtida assumindo um módulo de valor de 64 bits no tamanho do alfabeto. Para alfabetos pequenos (como os 62 caracteres da pergunta), isso leva a um viés desprezível. A segunda e a terceira propriedade são obtidas usando em RNGCryptoServiceProvidervez de System.Random.
using System;
using System.Security.Cryptography;publicstaticstringGetRandomAlphanumericString(int length){conststring alphanumericCharacters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ"+"abcdefghijklmnopqrstuvwxyz"+"0123456789";returnGetRandomString(length, alphanumericCharacters);}publicstaticstringGetRandomString(int length,IEnumerable<char> characterSet){if(length <0)thrownewArgumentException("length must not be negative","length");if(length >int.MaxValue/8)// 250 million chars ought to be enough for anybodythrownewArgumentException("length is too big","length");if(characterSet ==null)thrownewArgumentNullException("characterSet");var characterArray = characterSet.Distinct().ToArray();if(characterArray.Length==0)thrownewArgumentException("characterSet must not be empty","characterSet");var bytes =newbyte[length *8];var result =newchar[length];
using (var cryptoProvider =newRNGCryptoServiceProvider()){
cryptoProvider.GetBytes(bytes);}for(int i =0; i < length; i++){ulongvalue=BitConverter.ToUInt64(bytes, i *8);
result[i]= characterArray[value%(uint)characterArray.Length];}returnnewstring(result);}
Não há interseção com 64 x Z e Math.Pow (2, Y). Portanto, embora fazer números maiores reduza o viés, ele não o elimina. Atualizei minha resposta abaixo, minha abordagem era descartar entradas aleatórias e substituir por outro valor.
Todd
@ Eu sei que isso não elimina o viés, mas escolhi a simplicidade desta solução em vez de eliminar um viés praticamente irrelevante.
CodesInChaos
Concordo que, na maioria dos casos, é provavelmente praticamente irrelevante. Mas agora atualizei o meu para ser tão rápido quanto aleatório e um pouco mais seguro que o seu. Todos de código aberto para todos compartilharem. Sim, eu perdi tempo demais sobre isso ...
Todd
Se estamos usando o provedor RNG, temos alguma maneira de evitar viés na teoria? Não tenho certeza ... Se Todd está falando sério quando ele gera um número aleatório adicional (quando estamos na zona de viés), pode ser uma suposição errada. RNG tem distribuição quase linear de todos os valores gerados em média. Mas isso não significa que não teremos correlação local entre os bytes gerados. Assim, o byte adicional apenas para a zona de polarização ainda pode nos dar alguma polarização, mas devido a uma razão diferente. Muito provavelmente esse viés será muito pequeno. MAS, neste caso, o aumento do total de bytes gerados é uma maneira mais direta.
Maxim
1
@ Maxim Você pode usar a rejeição para eliminar completamente o viés (assumindo que o gerador subjacente seja perfeitamente aleatório). Em troca, o código pode ser arbitrariamente longo (com probabilidade exponencialmente pequena).
Se alguma vez você se preocupar, os alfabetos ingleses podem mudar em algum momento e você pode perder negócios, evitando o código rígido, mas deve ter um desempenho um pouco pior (comparável à Path.GetRandomFileNameabordagem)
publicstaticstringGetRandomAlphaNumeric(){var chars ='a'.To('z').Concat('0'.To('9')).ToList();returnnewstring(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());}publicstaticIEnumerable<char>To(thischar start,char end){if(end < start)thrownewArgumentOutOfRangeException("the end char should not be less than start char", innerException:null);returnEnumerable.Range(start, end - start +1).Select(i =>(char)i);}
As duas últimas abordagens parecem melhores se você puder torná-las um método de extensão por System.Randomexemplo.
Usar chars.Selecté muito feio, pois depende do tamanho da saída ser no máximo o tamanho do alfabeto.
CodesInChaos
@CodesInChaos Não tenho certeza se entendo você. Você quer dizer na 'a'.To('z')abordagem?
Nawfal #
1
1). chars.Select()Take (n) `só funciona se chars.Count >= n. Selecionar uma sequência que você realmente não usa é um pouco pouco intuitivo, especialmente com essa restrição implícita de comprimento. Eu prefiro usar Enumerable.Rangeou Enumerable.Repeat. 2) A mensagem de erro "o caractere final deve ser menor que o caractere inicial" é o caminho errado / ausente a not.
precisa saber é o seguinte
@CodesInChaos, mas no meu caso chars.Counté o caminho > n. Também não entendo a parte não intuitiva. Isso faz com que todos os usos Takenão sejam intuitivos, não é? Eu não acredito nisso. Obrigado por apontar o erro de digitação.
Nawfal
4
Isso é apresentado no theDailyWTF.com como um artigo do CodeSOD.
22
Apenas algumas comparações de desempenho das várias respostas neste tópico:
Testado no LinqPad. Para o tamanho da sequência de 10, gera:
de Linq = chdgmevhcy [10]
do loop = gtnoaryhxr [10]
de Select = rsndbztyby [10]
from GenerateRandomString = owyefjjakj [10]
de SecureFastRandom = VzougLYHYP [10]
de SecureFastRandom-NoCache = oVQXNGmO1S [10]
E os números de desempenho tendem a variar um pouco, muito ocasionalmente NonOptimizedé realmente mais rápido, e às vezes ForLoope GenerateRandomStringmudar quem está na liderança.
@Junto - para descobrir o que resulta em duplicatas, algo como var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, onde você substitui EachRandomizingMethodcom ... cada método
Pensei nisso, mas não conseguiu livrar-se dos caracteres não alfanuméricos como o segundo argumento é o caracteres alfabéticos não MÍNIMOS
ozzy432836
13
O código escrito por Eric J. é bastante desleixado (é claro que é de 6 anos atrás ... ele provavelmente não escreveria esse código hoje), e existem até alguns problemas.
Ao contrário de algumas das alternativas apresentadas, essa é criptograficamente sólida.
Falso ... Há um viés na senha (conforme escrito em um comentário), bcdefghé um pouco mais provável que os outros ( anão é porque, pelo GetNonZeroBytesfato de não estar gerando bytes com um valor zero, então o viés pois o aé equilibrado por ele), por isso não é realmente criptograficamente sólido.
Isso deve corrigir todos os problemas.
publicstaticstringGetUniqueKey(int size =6,string chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){
using (var crypto =newRNGCryptoServiceProvider()){var data =newbyte[size];// If chars.Length isn't a power of 2 then there is a bias if// we simply use the modulus operator. The first characters of// chars will be more probable than the last ones.// buffer used if we encounter an unusable random byte. We will// regenerate it in this bufferbyte[] smallBuffer =null;// Maximum random number that can be used without introducing a// biasint maxRandom =byte.MaxValue-((byte.MaxValue+1)% chars.Length);
crypto.GetBytes(data);var result =newchar[size];for(int i =0; i < size; i++){byte v = data[i];while(v > maxRandom){if(smallBuffer ==null){
smallBuffer =newbyte[1];}
crypto.GetBytes(smallBuffer);
v = smallBuffer[0];}
result[i]= chars[v % chars.Length];}returnnewstring(result);}}
Pergunta: Por que devo perder meu tempo usando, em Enumerable.Rangevez de digitar "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"?
using System;
using System.Collections.Generic;
using System.Linq;publicclassTest{publicstaticvoidMain(){var randomCharacters =GetRandomCharacters(8,true);Console.WriteLine(newstring(randomCharacters.ToArray()));}privatestaticList<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();}publicstaticIEnumerable<char>GetRandomCharacters(int count,bool includeLowerCase){var characters = getAvailableRandomCharacters(includeLowerCase);var random =newRandom();var result =Enumerable.Range(0, count).Select(_ => characters[random.Next(characters.Count)]);return result;}}
Resposta: Cordas mágicas são ruins. ALGUÉM notou que não havia "I " na minha corda no topo? Minha mãe me ensinou a não usar cordas mágicas por esse motivo ...
Nota 1: Como muitos outros como @dtb disseram, não use System.Randomse você precisar de segurança criptográfica ...
Nota 2: Esta resposta não é a mais eficiente ou a mais curta, mas eu queria que o espaço separasse a resposta da pergunta. O objetivo da minha resposta é mais alertar contra as cordas mágicas do que fornecer uma resposta inovadora e sofisticada.
Alfanumérico (caso de ignorância) é [A-Z0-9]. Se, por acidente, sua sequência aleatória apenas cobrir [A-HJ-Z0-9]o resultado, não cobrirá todo o intervalo permitido, o que pode ser problemático.
Wai Ha Lee
Como isso seria problemático? Portanto, não contém I. É porque há um personagem a menos e isso facilita a quebra? Quais são as estatísticas de senhas quebráveis que contêm 35 caracteres no intervalo que 36. Acho que prefiro arriscar ... ou apenas provar o intervalo de caracteres ... do que incluir todo esse lixo extra no meu código. Mas sou eu. Quero dizer, para não ser um buraco de bunda, só estou dizendo. Às vezes, acho que os programadores tendem a seguir a rota extra-complexa, a fim de serem extra-complexos.
Christine
1
Depende do caso de uso. É muito comum excluir caracteres como Ie Odesses tipos de seqüências aleatórias para evitar que os humanos os confundam com 1e 0. Se você não se importa em ter uma sequência legível por humanos, tudo bem, mas se for algo que alguém precise digitar, é realmente inteligente remover esses caracteres.
Chris Pratt
5
Uma versão ligeiramente mais limpa da solução da DTB.
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var random =newRandom();varlist=Enumerable.Repeat(0,8).Select(x=>chars[random.Next(chars.Length)]);returnstring.Join("",list);
Depois de revisar as outras respostas e considerar os comentários do CodeInChaos, junto com a resposta ainda tendenciosa (embora menor) do CodeInChaos, pensei que era necessária uma solução final de recortar e colar . Então, enquanto atualizava minha resposta, decidi dar tudo de si.
Relacionado a algumas outras respostas - Se você souber o tamanho da saída, não precisará de um StringBuilder e, ao usar o ToCharArray, isso cria e preenche a matriz (você não precisa criar uma matriz vazia primeiro)
Relacionando-se com outras respostas - Você deve usar o NextBytes, em vez de obter um de cada vez para obter desempenho
Tecnicamente, você pode fixar a matriz de bytes para obter acesso mais rápido. Geralmente, vale a pena iterar mais de 6 a 8 vezes em uma matriz de bytes. (Não feito aqui)
Uso do RNGCryptoServiceProvider para melhor aleatoriedade
Uso do armazenamento em cache de um buffer de 1 MB de dados aleatórios - o benchmarking mostra que a velocidade de acesso de bytes únicos em cache é ~ 1000x mais rápida - levando 9ms acima de 1MB contra 989ms para o cache.
Rejeição otimizada da zona de viés dentro da minha nova classe.
Solução final para a pergunta:
staticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];SecureFastRandom.GetNextBytesMax(rBytes, biasZone);for(var i =0; i <Length; i++){
rName[i]= charSet[rBytes[i]% charSet.Length];}returnnewstring(rName);}
Mas você precisa da minha nova classe (não testada):
/// <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>classSecureFastRandom{staticbyte[] byteCache =newbyte[1000000];//My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)staticint lastPosition =0;staticint remaining =0;/// <summary>/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function/// </summary>/// <param name="buffer"></param>publicstaticvoidDirectGetBytes(byte[] buffer){
using (var r =newRNGCryptoServiceProvider()){
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>publicstaticvoidGetBytes(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>publicstaticbyteGetByte(){lock(byteCache){returnUnsafeGetByte();}}/// <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>staticbyteUnsafeGetByte(){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>publicstaticvoidGetBytesWithMax(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 blocksDirectGetBytes(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>staticvoidUnsafeCheckBytesMax(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}}}
Para a história - minha solução mais antiga para esta resposta, usei o objeto Random:
privatestaticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();static rGen =newRandom();//Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);staticboolSlightlyMoreSecurityNeeded=true;//Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[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];}}returnnewstring(rName);}
Atuação:
SecureFastRandom - Primeira execução única = ~ 9-33ms . Imperceptível. Em andamento : 5ms (às vezes chega a 13ms) acima de 10.000 iterações, com uma única iteração média = 1,5 microssegundos.. Nota: Requer geralmente 2, mas ocasionalmente até 8 atualizações de cache - depende de quantos bytes únicos excedem a zona de polarização
Aleatório - Primeira execução única = ~ 0-1ms . Imperceptível. Em andamento : 5ms a mais de 10.000 iterações. Com uma única iteração média = 0,5 microssegundos. . Sobre a mesma velocidade.
Esses links são outra abordagem. O buffer poderia ser adicionado a essa nova base de código, mas o mais importante era explorar diferentes abordagens para remover desvios e comparar as velocidades e prós / contras.
1) Por que todas essas constantes mágicas? Você especificou o comprimento da saída três vezes. Apenas defina-o como uma constante ou um parâmetro. Você pode usar em charSet.Lengthvez de 62. 2) Uma estática Randomsem bloqueio significa que este código não é seguro para threads. 3) reduzir 0-255 mod 62 introduz um viés detectável. 4) Você não pode usar ToStringem uma matriz de caracteres, que sempre retorna "System.Char[]". Você precisa usar em seu new String(rName)lugar.
CodesInChaos
Obrigado @CodesInChaos, eu nunca pensei nessas coisas naquela época. Ainda usando apenas a classe Random, mas isso deve ser melhor. Eu não conseguia pensar em nenhuma maneira melhor de detectar e corrigir entradas tendenciosas.
Todd
É um pouco tolo começar com um RNG fraco ( System.Random) e evitar cuidadosamente qualquer viés no seu próprio código. A expressão "polir um bosta" vem à mente.
CodesInChaos
@CodesInChaos E agora o aprendiz superou seu mestre
Todd
4
Horrível, eu sei, mas não consegui me conter:
namespace ConsoleApplication2{
using System;
using System.Text.RegularExpressions;classProgram{staticvoidMain(string[] args){Random adomRng =newRandom();string rndString =string.Empty;char c;for(int i =0; i <8; i++){while(!Regex.IsMatch((c=Convert.ToChar(adomRng.Next(48,128))).ToString(),"[A-Za-z0-9]"));
rndString += c;}Console.WriteLine(rndString +Environment.NewLine);}}}
Eu estava procurando por uma resposta mais específica, onde desejasse controlar o formato da sequência aleatória e me deparei com este post. Por exemplo: matrículas (de carros) têm um formato específico (por país) e eu queria criar matrículas aleatórias.
Eu decidi escrever meu próprio método de extensão do Random para isso. (isso é para reutilizar o mesmo objeto aleatório, pois você pode dobrar em cenários com vários threads). Criei uma lista ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), mas também copio a classe de extensão aqui:
voidMain(){Random rnd =newRandom();
rnd.GetString("1-###-000").Dump();}publicstaticclassRandomExtensions{publicstaticstringGetString(thisRandom random,string format){// Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c// Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)StringBuilder result =newStringBuilder();for(int formatIndex =0; formatIndex < format.Length; formatIndex++){switch(format.ToUpper()[formatIndex]){case'0': result.Append(getRandomNumeric(random));break;case'#': result.Append(getRandomCharacter(random));break;default: result.Append(format[formatIndex]);break;}}return result.ToString();}privatestaticchar getRandomCharacter(Random random){string chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";return chars[random.Next(chars.Length)];}privatestaticchar getRandomNumeric(Random random){string nums ="0123456789";return nums[random.Next(nums.Length)];}}
Usar uma propriedade para algo que muda a cada acesso é bastante duvidoso. Eu recomendo usar um método.
CodesInChaos 11/01
2
RNGCryptoServiceProviderdeve ser descartado após o uso.
Tsahi Asher
Corrigi o problema de IDisposable, mas isso ainda é altamente duvidoso, criando um novo RNGCryptoServiceProvider para cada letra.
Piojo 7/11
@CodesInChaos done, agora um método.
Matas Vaitkevicius 17/04
3
Tente combinar duas partes: única (sequência, contador ou data) e aleatória
publicclassRandomStringGenerator{publicstaticstringGen(){returnConvertToBase(DateTime.UtcNow.ToFileTimeUtc())+GenRandomStrings(5);//keep length fixed at least of one part}privatestaticstringGenRandomStrings(int strLen){var result =string.Empty;varGen=newRNGCryptoServiceProvider();var data =newbyte[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;}privatestaticstringConvertToBase(long num,int nbase =36){var chars ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//if you wish make algorithm more secure - change order of letter here// check if we can convert to another baseif(nbase <2|| nbase > chars.Length)returnnull;int r;var newNumber =string.Empty;// in r we have the offset of the char that was converted to the new basewhile(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;}}
1) Você pode usar literais de caracteres em vez dos valores ASCII associados a esses caracteres. 2) Você tem um erro de um por um no seu código de correspondência de intervalo. Você precisa usar <=e em >=vez de <e >. 3) Eu adicionaria os parênteses desnecessários em torno das &&expressões para deixar claro que elas têm precedência, mas é claro que isso é apenas uma escolha estilística.
CodesInChaos
+ 1 Bom para remover o viés e adicionar testes. Não sei por que você precede sua sequência aleatória com uma sequência derivada de carimbo de data / hora. Além disso, você ainda precisa descartar seu RNGCryptoServiceProvider
Monty
2
Uma solução sem usar Random:
var chars =Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",8);var randomStr =newstring(chars.SelectMany(str => str).OrderBy(c =>Guid.NewGuid()).Take(8).ToArray());
O NewGuid usa aleatoriamente internamente. Então, isso ainda está usando aleatoriamente, está apenas escondendo.
Wedge
2
Aqui está uma variante da solução de Eric J, ou seja, criptograficamente sólida, para o WinRT (Windows Store App):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newStringBuilder(length);for(int i =0; i < length;++i){
result.Append(CryptographicBuffer.GenerateRandomNumber()% chars.Length);}return result.ToString();}
Se o desempenho for importante (especialmente quando o comprimento for alto):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newSystem.Text.StringBuilder(length);var bytes =CryptographicBuffer.GenerateRandom((uint)length *4).ToArray();for(int i =0; i < bytes.Length; i +=4){
result.Append(BitConverter.ToUInt32(bytes, i)% chars.Length);}return result.ToString();}
Isso não é criptograficamente correto. Há um pequeno viés devido à operação do módulo que não espalha a largura inteira do ulong igualmente em 62 caracteres.
Lie Ryan
1
Eu sei que este não é o melhor caminho. Mas você pode tentar isso.
string str =Path.GetRandomFileName();//This method returns a random file name of 11 characters
str = str.Replace(".","");Console.WriteLine("Random string: "+ str);
Como é essa linha? Console.WriteLine ($ "String aleatória: {Path.GetRandomFileName (). Replace (". "," ")}"); é uma linha.
PmanAce
1
Eu não sei o quão criptograficamente isso é, mas é mais legível e conciso do que as soluções mais complexas de longe (imo), e deve ser mais "aleatório" do que as System.Randomsoluções baseadas.
Concedido, não é otimizado para velocidade, portanto, se é essencial gerar milhões de seqüências aleatórias a cada segundo, tente outra!
NOTA: Esta solução não permite repetições de símbolos no alfabeto, e o alfabeto DEVE ter tamanho igual ou superior ao da string de saída, tornando essa abordagem menos desejável em algumas circunstâncias, tudo depende do seu caso de uso.
Se seus valores não são completamente aleatórios, mas na verdade podem depender de algo - você pode calcular um hash md5 ou sha1 desse 'algo' e depois truncá-lo no tamanho que desejar.
1) métodos estáticos devem ser seguros para discussão. 2) Qual o sentido de incrementar o índice em vez de usar o resultado random.Nextdiretamente? Complica o código e não alcança nada útil.
CodesInChaos
0
Aqui está um mecanismo para gerar uma sequência alfanumérica aleatória (eu uso isso para gerar senhas e dados de teste) sem definir o alfabeto e os números,
CleanupBase64 removerá as partes necessárias na string e continuará adicionando letras alfanuméricas aleatórias recursivamente.
publicstaticstringGenerateRandomString(int length){var numArray =newbyte[length];newRNGCryptoServiceProvider().GetBytes(numArray);returnCleanUpBase64String(Convert.ToBase64String(numArray), length);}privatestaticstringCleanUpBase64String(string input,int maxLength){
input = input.Replace("-","");
input = input.Replace("=","");
input = input.Replace("/","");
input = input.Replace("+","");
input = input.Replace(" ","");while(input.Length< maxLength)
input = input +GenerateRandomString(maxLength);return input.Length<= maxLength ?
input.ToUpper()://In my case I want capital letters
input.ToUpper().Substring(0, maxLength);}
Você declarou GenerateRandomStringe telefonou GetRandomStringde dentro SanitiseBase64String. Além disso, você ter declarado SanitiseBase64String e chamada CleanUpBase64Stringem GenerateRandomString.
não tenho 100% de certeza, já que não testei TODAS as opções aqui, mas das que testei, essa é a mais rápida. cronometrou-o com cronômetro e mostrou 9-10 ticks; portanto, se a velocidade é mais importante que a segurança, tente o seguinte:
privatestaticRandom random =newRandom();publicstaticstringRandom(int length){var stringChars =newchar[length];for(int i =0; i < length; i++){
stringChars[i]=(char)random.Next(0x30,0x7a);returnnewstring(stringChars);}}
Random
classe para gerar senhas. A semeaduraRandom
tem entropia muito baixa, portanto não é realmente seguro. Use um PRNG criptográfico para senhas.Respostas:
Ouvi dizer que o LINQ é o novo preto, então aqui está minha tentativa de usar o LINQ:
(Observação: o uso da
Random
classe torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use aRNGCryptoServiceProvider
classe se precisar de um gerador de números aleatórios forte.)fonte
return new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Não é tão elegante quanto a solução Linq.
(Observação: o uso da
Random
classe torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use aRNGCryptoServiceProvider
classe se precisar de um gerador de números aleatórios forte.)fonte
GetRandomFileName
solução de Adam Porad é mais rápida, mas não permite nenhum controle dos caracteres utilizados e o tamanho máximo possível é de 11 caracteres. AGuid
solução de Douglas é extremamente rápida, mas os caracteres são restritos a A-F0-9 e o comprimento máximo possível é de 32 caracteres.GetRandomFileName
mas (a) perderia sua vantagem de desempenho e (b) seu código se tornaria mais complicado.System.Random
não é adequado para segurança.Ao contrário de algumas das alternativas apresentadas, essa é criptograficamente sólida .
Baseado em uma discussão de alternativas aqui e atualizado / modificado com base nos comentários abaixo.
Aqui está um pequeno equipamento de teste que demonstra a distribuição de caracteres na saída antiga e atualizada. Para uma discussão profunda da análise da aleatoriedade , consulte random.org.
fonte
RNGCSP
em primeiro lugar?) Usando mod para indexar noschars
meios de matriz que você vai ser tendenciosa saída a menos quechars.Length
passa a ser um divisor de 256.4*maxSize
bytes aleatórios e usar(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length
. Eu também usaria emGetBytes
vez deGetNonZeroBytes
. E, finalmente, você pode remover a primeira chamada paraGetNonZeroBytes
. Você não está usando o resultado.Solução 1 - maior 'faixa' com comprimento mais flexível
Esta solução tem mais alcance do que usar um GUID porque um GUID possui alguns bits fixos que são sempre os mesmos e, portanto, não aleatórios, por exemplo, o caractere 13 em hexadecimal é sempre "4" - pelo menos em um GUID da versão 6.
Essa solução também permite gerar uma sequência de qualquer tamanho.
Solução 2 - Uma linha de código - válida para até 22 caracteres
Você não pode gerar cadeias de caracteres desde que a Solução 1 e a cadeia de caracteres não tenham o mesmo intervalo devido a bits fixos nos GUIDs, mas em muitos casos isso fará o trabalho.
Solução 3 - um pouco menos de código
Principalmente mantendo isso aqui para fins históricos. Ele usa um pouco menos de código, que, apesar de custar menos, tem um alcance - porque usa hex em vez de base64, são necessários mais caracteres para representar o mesmo intervalo em comparação com as outras soluções.
O que significa mais chances de colisão - testá-lo com 100.000 iterações de 8 cadeias de caracteres gerou uma duplicata.
fonte
Aqui está um exemplo que eu roubei do exemplo de Sam Allen no Dot Net Perls
Se você precisar apenas de 8 caracteres, use Path.GetRandomFileName () no espaço para nome System.IO. Sam diz que o uso do método "Path.GetRandomFileName aqui às vezes é superior, porque usa RNGCryptoServiceProvider para obter melhor aleatoriedade. No entanto, é limitado a 11 caracteres aleatórios".
GetRandomFileName sempre retorna uma cadeia de 12 caracteres com um ponto no nono caractere. Portanto, você precisará retirar o período (já que isso não é aleatório) e, em seguida, pegar 8 caracteres da sequência. Na verdade, você pode apenas pegar os 8 primeiros caracteres e não se preocupar com o período.
PS: obrigado Sam
fonte
Os principais objetivos do meu código são:
A primeira propriedade é obtida assumindo um módulo de valor de 64 bits no tamanho do alfabeto. Para alfabetos pequenos (como os 62 caracteres da pergunta), isso leva a um viés desprezível. A segunda e a terceira propriedade são obtidas usando em
RNGCryptoServiceProvider
vez deSystem.Random
.fonte
O mais simples:
Você pode obter um melhor desempenho se codificar a matriz char e confiar em
System.Random
:Se alguma vez você se preocupar, os alfabetos ingleses podem mudar em algum momento e você pode perder negócios, evitando o código rígido, mas deve ter um desempenho um pouco pior (comparável à
Path.GetRandomFileName
abordagem)As duas últimas abordagens parecem melhores se você puder torná-las um método de extensão por
System.Random
exemplo.fonte
chars.Select
é muito feio, pois depende do tamanho da saída ser no máximo o tamanho do alfabeto.'a'.To('z')
abordagem?chars.Select()
Take (n) `só funciona sechars.Count >= n
. Selecionar uma sequência que você realmente não usa é um pouco pouco intuitivo, especialmente com essa restrição implícita de comprimento. Eu prefiro usarEnumerable.Range
ouEnumerable.Repeat
. 2) A mensagem de erro "o caractere final deve ser menor que o caractere inicial" é o caminho errado / ausente anot
.chars.Count
é o caminho> n
. Também não entendo a parte não intuitiva. Isso faz com que todos os usosTake
não sejam intuitivos, não é? Eu não acredito nisso. Obrigado por apontar o erro de digitação.Apenas algumas comparações de desempenho das várias respostas neste tópico:
Métodos e configuração
Resultados
Testado no LinqPad. Para o tamanho da sequência de 10, gera:
E os números de desempenho tendem a variar um pouco, muito ocasionalmente
NonOptimized
é realmente mais rápido, e às vezesForLoop
eGenerateRandomString
mudar quem está na liderança.fonte
var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());
, onde você substituiEachRandomizingMethod
com ... cada métodoUma linha de código
Membership.GeneratePassword()
faz o truque :)Aqui está uma demonstração para o mesmo.
fonte
O código escrito por Eric J. é bastante desleixado (é claro que é de 6 anos atrás ... ele provavelmente não escreveria esse código hoje), e existem até alguns problemas.
Falso ... Há um viés na senha (conforme escrito em um comentário),
bcdefgh
é um pouco mais provável que os outros (a
não é porque, peloGetNonZeroBytes
fato de não estar gerando bytes com um valor zero, então o viés pois oa
é equilibrado por ele), por isso não é realmente criptograficamente sólido.Isso deve corrigir todos os problemas.
fonte
Também usamos aleatoriamente uma string personalizada, mas implementamos como auxiliar de uma string, por isso fornece alguma flexibilidade ...
Uso
ou
fonte
Meu código de uma linha simples funciona para mim :)
Para expandir isso para qualquer string de comprimento
fonte
Outra opção poderia ser usar o Linq e agregar caracteres aleatórios em um construtor de strings.
fonte
Pergunta: Por que devo perder meu tempo usando, em
Enumerable.Range
vez de digitar"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?Resposta: Cordas mágicas são ruins. ALGUÉM notou que não havia "
I
" na minha corda no topo? Minha mãe me ensinou a não usar cordas mágicas por esse motivo ...Nota 1: Como muitos outros como @dtb disseram, não use
System.Random
se você precisar de segurança criptográfica ...Nota 2: Esta resposta não é a mais eficiente ou a mais curta, mas eu queria que o espaço separasse a resposta da pergunta. O objetivo da minha resposta é mais alertar contra as cordas mágicas do que fornecer uma resposta inovadora e sofisticada.
fonte
I
?"[A-Z0-9]
. Se, por acidente, sua sequência aleatória apenas cobrir[A-HJ-Z0-9]
o resultado, não cobrirá todo o intervalo permitido, o que pode ser problemático.I
. É porque há um personagem a menos e isso facilita a quebra? Quais são as estatísticas de senhas quebráveis que contêm 35 caracteres no intervalo que 36. Acho que prefiro arriscar ... ou apenas provar o intervalo de caracteres ... do que incluir todo esse lixo extra no meu código. Mas sou eu. Quero dizer, para não ser um buraco de bunda, só estou dizendo. Às vezes, acho que os programadores tendem a seguir a rota extra-complexa, a fim de serem extra-complexos.I
eO
desses tipos de seqüências aleatórias para evitar que os humanos os confundam com1
e0
. Se você não se importa em ter uma sequência legível por humanos, tudo bem, mas se for algo que alguém precise digitar, é realmente inteligente remover esses caracteres.Uma versão ligeiramente mais limpa da solução da DTB.
Suas preferências de estilo podem variar.
fonte
fonte
Depois de revisar as outras respostas e considerar os comentários do CodeInChaos, junto com a resposta ainda tendenciosa (embora menor) do CodeInChaos, pensei que era necessária uma solução final de recortar e colar . Então, enquanto atualizava minha resposta, decidi dar tudo de si.
Para uma versão atualizada desse código, visite o novo repositório Hg no Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Eu recomendo que você copie e cole o código em: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer (certifique-se que você clique o botão Raw para facilitar a cópia e garantir que você tenha a versão mais recente, acho que esse link vai para uma versão específica do código, não a mais recente).
Notas atualizadas:
Solução final para a pergunta:
Mas você precisa da minha nova classe (não testada):
Para a história - minha solução mais antiga para esta resposta, usei o objeto Random:
Atuação:
Verifique também:
Esses links são outra abordagem. O buffer poderia ser adicionado a essa nova base de código, mas o mais importante era explorar diferentes abordagens para remover desvios e comparar as velocidades e prós / contras.
fonte
charSet.Length
vez de62
. 2) Uma estáticaRandom
sem bloqueio significa que este código não é seguro para threads. 3) reduzir 0-255 mod 62 introduz um viés detectável. 4) Você não pode usarToString
em uma matriz de caracteres, que sempre retorna"System.Char[]"
. Você precisa usar em seunew String(rName)
lugar.System.Random
) e evitar cuidadosamente qualquer viés no seu próprio código. A expressão "polir um bosta" vem à mente.Horrível, eu sei, mas não consegui me conter:
fonte
Eu estava procurando por uma resposta mais específica, onde desejasse controlar o formato da sequência aleatória e me deparei com este post. Por exemplo: matrículas (de carros) têm um formato específico (por país) e eu queria criar matrículas aleatórias.
Eu decidi escrever meu próprio método de extensão do Random para isso. (isso é para reutilizar o mesmo objeto aleatório, pois você pode dobrar em cenários com vários threads). Criei uma lista ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), mas também copio a classe de extensão aqui:
fonte
Agora no sabor de uma linha.
fonte
RNGCryptoServiceProvider
deve ser descartado após o uso.Tente combinar duas partes: única (sequência, contador ou data) e aleatória
Testes:
fonte
<=
e em>=
vez de<
e>
. 3) Eu adicionaria os parênteses desnecessários em torno das&&
expressões para deixar claro que elas têm precedência, mas é claro que isso é apenas uma escolha estilística.Uma solução sem usar
Random
:fonte
Aqui está uma variante da solução de Eric J, ou seja, criptograficamente sólida, para o WinRT (Windows Store App):
Se o desempenho for importante (especialmente quando o comprimento for alto):
fonte
Eu sei que este não é o melhor caminho. Mas você pode tentar isso.
fonte
Eu não sei o quão criptograficamente isso é, mas é mais legível e conciso do que as soluções mais complexas de longe (imo), e deve ser mais "aleatório" do que as
System.Random
soluções baseadas.Não consigo decidir se acho que esta versão ou a próxima é "mais bonita", mas elas fornecem exatamente os mesmos resultados:
Concedido, não é otimizado para velocidade, portanto, se é essencial gerar milhões de seqüências aleatórias a cada segundo, tente outra!
NOTA: Esta solução não permite repetições de símbolos no alfabeto, e o alfabeto DEVE ter tamanho igual ou superior ao da string de saída, tornando essa abordagem menos desejável em algumas circunstâncias, tudo depende do seu caso de uso.
fonte
Se seus valores não são completamente aleatórios, mas na verdade podem depender de algo - você pode calcular um hash md5 ou sha1 desse 'algo' e depois truncá-lo no tamanho que desejar.
Além disso, você pode gerar e truncar um guia.
fonte
fonte
random.Next
diretamente? Complica o código e não alcança nada útil.Aqui está um mecanismo para gerar uma sequência alfanumérica aleatória (eu uso isso para gerar senhas e dados de teste) sem definir o alfabeto e os números,
CleanupBase64 removerá as partes necessárias na string e continuará adicionando letras alfanuméricas aleatórias recursivamente.
fonte
GenerateRandomString
e telefonouGetRandomString
de dentroSanitiseBase64String
. Além disso, você ter declaradoSanitiseBase64String
e chamadaCleanUpBase64String
emGenerateRandomString
.Há um dos pacotes de nuget impressionantes que tornam isso tão simples.
Um dos bons exemplos está aqui .
fonte
não tenho 100% de certeza, já que não testei TODAS as opções aqui, mas das que testei, essa é a mais rápida. cronometrou-o com cronômetro e mostrou 9-10 ticks; portanto, se a velocidade é mais importante que a segurança, tente o seguinte:
fonte