Tenga en cuenta que NO debe usar ningún método basado en la Randomclase para generar contraseñas. La siembra de Randomtiene una entropía muy baja, por lo que no es realmente segura. Use un PRNG criptográfico para las contraseñas.
CodesInChaos
2
Sería bueno incluir la localización del idioma en esta pregunta. ¡Especialmente si su interfaz gráfica de usuario necesita atender chino o búlgaro!
Peter Jamsmenson el
15
Algo con tantos votos a favor y tantas respuestas de calidad no merece ser marcado como cerrado. Voto para que se vuelva a abrir.
John Coleman
Respuestas:
1686
Escuché que LINQ es el nuevo negro, así que aquí está mi intento de usar LINQ:
privatestaticRandom random =newRandom();publicstaticstringRandomString(int length){conststring chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";returnnewstring(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
(Nota: el uso de la Randomclase hace que esto sea inadecuado para cualquier cosa relacionada con la seguridad , como crear contraseñas o tokens. Use la RNGCryptoServiceProviderclase si necesita un generador de números aleatorios seguro).
@ Alex: He realizado algunas pruebas rápidas y parece escalar de forma bastante lineal cuando se generan cadenas más largas (siempre que haya suficiente memoria disponible). Dicho esto, la respuesta de Dan Rigby fue casi el doble de rápida que esta en cada prueba.
LukeH
66
Bien. Si su criterio es que usa linq y que tiene una narrativa de código pésima, entonces definitivamente son las rodillas de la abeja. Tanto la narrativa del código como la ruta de ejecución real son bastante ineficientes e indirectas. No me malinterpreten, soy un gran inconformista de código (me encanta Python), pero esto es más o menos una máquina de Rube Goldberg.
eremzeit
55
Si bien esto técnicamente responde a la pregunta, su salida es muy engañosa. La generación de sonidos 8 caracteres aleatorios como no puede haber muy muchos resultados, mientras que esto produce en el mejor de 2 mil millones de resultados diferentes. Y en la práctica aún menos. También debe agregar una advertencia GRANDE GRASA para no usar esto para nada relacionado con la seguridad.
CodesInChaos
41
@xaisoft: las letras minúsculas se dejan como ejercicio para el lector.
dtb
15
La siguiente línea es más eficiente en memoria (y, por lo tanto, tiempo) que la dadareturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams el
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);
No es tan elegante como la solución Linq.
(Nota: el uso de la Randomclase hace que esto sea inadecuado para cualquier cosa relacionada con la seguridad , como crear contraseñas o tokens. Use la RNGCryptoServiceProviderclase si necesita un generador de números aleatorios seguro).
@Alex: Esta no es la respuesta más rápida absoluta, pero es la respuesta "real" más rápida (es decir, de aquellas que permiten el control sobre los caracteres utilizados y la longitud de la cadena).
LukeH
2
@Alex: la GetRandomFileNamesolución de Adam Porad es más rápida pero no permite ningún control de los caracteres utilizados y la longitud máxima posible es de 11 caracteres. La Guidsolución de Douglas es ultrarrápida, pero los caracteres están restringidos a A-F0-9 y la longitud máxima posible es de 32 caracteres.
LukeH
1
@ Adam: Sí, podría concatenar el resultado de múltiples llamadas a, GetRandomFileNamepero luego (a) perdería su ventaja de rendimiento y (b) su código se volvería más complicado.
LukeH
2
@xaisoft crea tu instancia del objeto Random () fuera de tu bucle. Si crea muchas instancias de Random () en un intervalo corto, la llamada a .Next () devolverá el mismo valor que Random () utiliza una semilla basada en el tiempo.
Dan Rigby
2
@xaisoft No use esta respuesta para nada crítico para la seguridad, como contraseñas. System.RandomNo es adecuado para la seguridad.
CodesInChaos
333
ACTUALIZADO según los comentarios. La implementación original generó ah ~ 1.95% del tiempo y los caracteres restantes ~ 1.56% del tiempo. La actualización genera todos los caracteres ~ 1.61% del tiempo.
SOPORTE DE MARCO: .NET Core 3 (y futuras plataformas que admitan .NET Standard 2.1 o superior) proporciona un método criptográficamente sólido RandomNumberGenerator.GetInt32 () para generar un entero aleatorio dentro de un rango deseado.
A diferencia de algunas de las alternativas presentadas, esta es criptográficamente 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();}}}
Basado en una discusión de alternativas aquí y actualizado / modificado según los comentarios a continuación.
Aquí hay un pequeño arnés de prueba que demuestra la distribución de caracteres en la salida anterior y actualizada. Para una discusión profunda del análisis de aleatoriedad , visite 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")}%");}}}}
Este parece ser el enfoque correcto para mí: las contraseñas aleatorias, las sales, la entropía, etc. no deben generarse utilizando Random (), que está optimizado para la velocidad y genera secuencias reproducibles de números; RNGCryptoServiceProvider.GetNonZeroBytes () por otro lado produce secuencias salvajes de números que NO son reproducibles.
mindplay.dk
25
Las letras están ligeramente sesgadas (255% 62! = 0). A pesar de este pequeño defecto, es la mejor solución aquí.
CodesInChaos
13
Tenga en cuenta que esto no es correcto si desea una fuerza criptográfica, aleatoriedad imparcial. (Y si no quieres eso, ¿por qué usarlo RNGCSPen primer lugar?) Usar mod para indexar en la charsmatriz significa que obtendrás una salida sesgada a menos chars.Lengthque sea un divisor de 256.
LukeH
15
Una posibilidad para reducir mucho el sesgo es solicitar 4*maxSizebytes aleatorios y luego usarlos (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. También lo usaría en GetByteslugar de GetNonZeroBytes. Y finalmente puedes eliminar la primera llamada a GetNonZeroBytes. No estás usando su resultado.
CodesInChaos
14
Dato curioso: AZ az 0-9 tiene 62 caracteres. La gente señala el sesgo de las letras porque 256% 62! = 0. Las identificaciones de video de YouTube son AZ az 0-9, así como "-" y "_", que producen 64 caracteres posibles, que se dividen en 256 de manera uniforme. ¿Coincidencia? ¡Yo creo que no! :)
qJake
200
Solución 1: el 'rango' más grande con la longitud más flexible
Esta solución tiene más alcance que usar un GUID porque un GUID tiene un par de bits fijos que siempre son iguales y, por lo tanto, no aleatorios, por ejemplo, el carácter de 13 en hexadecimal siempre es "4", al menos en un GUID de la versión 6.
Esta solución también le permite generar una cadena de cualquier longitud.
Solución 2: una línea de código, válida para hasta 22 caracteres
No puede generar cadenas siempre que la Solución 1 y la cadena no tengan el mismo rango debido a bits fijos en los GUID, pero en muchos casos esto hará el trabajo.
Solución 3: un poco menos de código
Guid.NewGuid().ToString("n").Substring(0,8);
Principalmente manteniendo esto aquí para fines históricos. Utiliza un poco menos de código, lo que sin embargo implica el gasto de tener menos rango, ya que usa hexadecimal en lugar de base64, se necesitan más caracteres para representar el mismo rango en comparación con las otras soluciones.
Lo que significa más posibilidades de colisión: probarlo con 100,000 iteraciones de 8 cadenas de caracteres generó un duplicado.
¿Realmente generaste un duplicado? Sorprendente en 5,316,911,983,139,663,491,615,228,241,121,400,000 posibles combinaciones de GUID.
Alex
73
@Alex: está acortando el GUID a 8 caracteres, por lo que la probabilidad de colisiones es mucho mayor que la de los GUID.
dtb
23
Nadie puede apreciar esto aparte de los nerds :) Sí, tienes toda la razón, el límite de 8 caracteres hace la diferencia.
Alex
31
Guid.NewGuid (). ToString ("n") mantendrá los guiones, no se necesita la llamada Reemplazar (). Pero debe mencionarse, los GUID son solo 0-9 y AF. El número de combinaciones es "suficientemente bueno", pero no se acerca a lo que permite una cadena aleatoria alfanumérica verdadera . Las posibilidades de colisión son 1: 4,294,967,296, lo mismo que un entero aleatorio de 32 bits.
richardtallent
32
1) Los GUID están diseñados para ser únicos, no aleatorios. Si bien las versiones actuales de Windows generan GUID V4 que de hecho son aleatorios, eso no está garantizado. Por ejemplo, las versiones anteriores de Windows usaban GUID V1, donde su error podría fallar. 2) Solo usar caracteres hexadecimales reduce significativamente la calidad de la cadena aleatoria. De 47 a 32 bits. 3) Las personas están subestimando la probabilidad de colisión, ya que la dan para parejas individuales. Si genera 100k valores de 32 bits, probablemente tenga una colisión entre ellos. Ver problema de cumpleaños.
CodesInChaos
72
Aquí hay un ejemplo que robé del ejemplo de Sam Allen en Dot Net Perls
Si solo necesita 8 caracteres, use Path.GetRandomFileName () en el espacio de nombres System.IO. Sam dice que usar el método "Path.GetRandomFileName aquí es a veces superior, porque usa RNGCryptoServiceProvider para una mejor aleatoriedad. Sin embargo, está limitado a 11 caracteres aleatorios".
GetRandomFileName siempre devuelve una cadena de 12 caracteres con un punto en el noveno carácter. Por lo tanto, deberá eliminar el punto (ya que no es aleatorio) y luego tomar 8 caracteres de la cadena. En realidad, puedes tomar los primeros 8 caracteres y no preocuparte por el período.
Esto funciona bien Lo ejecuté a través de 100,000 iteraciones y nunca tuve un nombre duplicado. Sin embargo, yo me encuentro varias palabras vulgares (en Inglés). Ni siquiera habría pensado en esto, excepto que uno de los primeros en la lista tenía F ***. Solo un aviso si usa esto para algo que el usuario verá.
Techturtle
3
@techturtle Gracias por la advertencia. Supongo que existe el riesgo de palabras vulgares con cualquier generación de cadenas al azar que use todas las letras del alfabeto.
Adam Porad
agradable y simple pero no es bueno para una cadena larga ... vote por este buen truco
Maher Abuthraa
Este método parece devolver solo cadenas alfanuméricas en minúsculas.
jaybro
2
Hay palabras vulgares de vez en cuando, pero si mantienes esto funcionando el tiempo suficiente, finalmente escribe Shakespeare. (Solo unas pocas vidas del universo. :)
Slothario
38
Los objetivos principales de mi código son:
La distribución de las cadenas es casi uniforme (no importa las desviaciones menores, siempre que sean pequeñas)
Produce más de unos pocos miles de millones de cadenas para cada conjunto de argumentos. Generar una cadena de 8 caracteres (~ 47 bits de entropía) no tiene sentido si su PRNG solo genera 2 mil millones (31 bits de entropía) de valores diferentes.
Es seguro, ya que espero que la gente use esto para contraseñas u otros tokens de seguridad.
La primera propiedad se logra tomando un módulo de valor de 64 bits del tamaño del alfabeto. Para alfabetos pequeños (como los 62 caracteres de la pregunta) esto lleva a un sesgo insignificante. La segunda y tercera propiedad se logran utilizando en RNGCryptoServiceProviderlugar 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);}
No hay intersección con 64 x Z y Math.Pow (2, Y). Entonces, si bien hacer números más grandes reduce el sesgo, no lo elimina. Actualicé mi respuesta a continuación, mi enfoque era descartar entradas aleatorias y reemplazarlas con otro valor.
Todd
@Todd Sé que no elimina el sesgo, pero elegí la simplicidad de esta solución en lugar de eliminar un sesgo prácticamente irrelevante.
CodesInChaos
Estoy de acuerdo en la mayoría de los casos, probablemente sea prácticamente irrelevante. Pero ahora he actualizado el mío para que sea tan rápido como aleatorio y un poco más seguro que el tuyo. Todo de código abierto para que todos lo compartan. Sí, perdí demasiado tiempo en esto ...
Todd
Si estamos utilizando un proveedor de RNG, ¿tenemos alguna forma de evitar sesgos en teoría? No estoy seguro ... Si Todd se refiere a la forma en que genera un número aleatorio adicional (cuando estamos en la zona de sesgo), entonces puede ser una suposición errónea. RNG tiene una distribución casi lineal de todos los valores generados en promedio. Pero eso no significa que no tendremos correlación local entre los bytes generados. Por lo tanto, el byte adicional solo para la zona de sesgo todavía puede darnos algún sesgo, pero debido a diferentes razones. Lo más probable es que este sesgo sea muy pequeño. PERO en este caso, el aumento del total de bytes generados es una forma más sencilla.
Maxim
1
@Maxim Puede usar el rechazo para eliminar completamente el sesgo (suponiendo que el generador subyacente sea perfectamente aleatorio). A cambio, el código puede correr arbitrariamente largo (con una probabilidad exponencialmente pequeña)
Si alguna vez le preocupa, los alfabetos en inglés pueden cambiar en algún momento y puede perder negocios, entonces puede evitar la codificación rígida, pero debería funcionar ligeramente peor (comparable al Path.GetRandomFileNameenfoque)
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);}
Los dos últimos enfoques se ven mejor si puede convertirlos en un método de extensión, por System.Randomejemplo.
El uso chars.Selectes muy feo ya que depende del tamaño de salida como máximo del tamaño del alfabeto.
CodesInChaos
@CodesInChaos No estoy seguro si te entiendo. ¿Quieres decir en el 'a'.To('z')enfoque?
nawfal
1
1) chars.Select().Take (n) `solo funciona si chars.Count >= n. Seleccionar una secuencia que en realidad no utilizas es poco intuitiva, especialmente con esa restricción de longitud implícita. Prefiero usar Enumerable.Rangeo Enumerable.Repeat. 2) El mensaje de error "el carácter final debe ser menor que el carácter inicial" es el camino equivocado / falta a not.
CodesInChaos
@CodesInChaos pero en mi caso chars.Countes así > n. Además, no entiendo la parte no intuitiva. ¿Eso hace que todos los usos Takeno sean intuitivos? No lo creo Gracias por señalar el error tipográfico.
nawfal
44
Esto aparece en theDailyWTF.com como un artículo de CodeSOD.
22
Solo algunas comparaciones de rendimiento de las diversas respuestas en este hilo:
Probado en LinqPad. Para un tamaño de cadena de 10, genera:
de Linq = chdgmevhcy [10]
de Loop = gtnoaryhxr [10]
desde Seleccionar = rsndbztyby [10]
from GenerateRandomString = owyefjjakj [10]
de SecureFastRandom = VzougLYHYP [10]
de SecureFastRandom-NoCache = oVQXNGmO1S [10]
Y las cifras de rendimiento tienden a variar un poco, muy de vez en cuando NonOptimizeden realidad es más rápido, y, a veces ForLoop, y GenerateRandomStringel interruptor que está en la delantera.
Sería interesante saber cuáles crearon embaucados.
Rebecca
@Junto - averiguar qué resultados por duplicado, algo así como var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, en los que se reemplaza EachRandomizingMethodcon cada método ...
Pensé en eso, pero no pude deshacerme de los caracteres no alfanuméricos, ya que el segundo argumento son los caracteres MÍNIMOS no alfa
ozzy432836
13
El código escrito por Eric J. es bastante descuidado (está bastante claro que es de hace 6 años ... probablemente no escribiría ese código hoy), e incluso hay algunos problemas.
A diferencia de algunas de las alternativas presentadas, esta es criptográficamente sólida.
No es cierto ... Hay un sesgo en la contraseña (como está escrito en un comentario), bcdefghson un poco más probables que los demás ( ano lo es porque GetNonZeroBytesno genera bytes con un valor de cero, por lo que el sesgo porque aestá equilibrado por él), por lo que no es realmente criptográficamente sólido.
Esto debería corregir todos los 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);}}
Pregunta: ¿Por qué debería perder mi tiempo usando en Enumerable.Rangelugar de escribir "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;}}
Respuesta: Las cuerdas mágicas son MALAS. ¿ALGUIEN notó que no había " I" en mi cadena en la parte superior? Mi madre me enseñó a no usar cuerdas mágicas por esta misma razón ...
Nota 1: como muchos otros como @dtb dijeron, no lo use System.Randomsi necesita seguridad criptográfica ...
Nota 2: Esta respuesta no es la más eficiente ni la más breve, pero quería que el espacio separara la respuesta de la pregunta. El propósito de mi respuesta es más advertir contra los hilos mágicos que proporcionar una respuesta innovadora y elegante.
Alfanumérico (ignorando el caso) es [A-Z0-9]. Si, por accidente, su cadena aleatoria solo cubre [A-HJ-Z0-9]el resultado, no cubre el rango completo permitido, lo que puede ser problemático.
Wai Ha Lee
¿Cómo sería eso problemático? Entonces no contiene I. ¿Es porque hay un personaje menos y eso hace que sea más fácil de descifrar? ¿Cuáles son las estadísticas sobre las contraseñas descifrables que contienen 35 caracteres en el rango de 36. Creo que prefiero arriesgarme ... o simplemente probar el rango de caracteres ... que incluir toda esa basura extra en mi código. Pero ese soy yo. Quiero decir, no ser un agujero en el trasero, solo digo. A veces pienso que los programadores tienen una tendencia a ir por la ruta extra compleja por el simple hecho de ser extracomplejos.
Christine
1
Se profundiza en el caso de uso. Es muy común excluir caracteres como Iy Ode este tipo de cadenas aleatorias para evitar que los humanos los confundan con 1y 0. Si no te importa tener una cadena legible por humanos, está bien, pero si es algo que alguien podría necesitar escribir, entonces es realmente inteligente eliminar esos caracteres.
Chris Pratt
5
Una versión ligeramente más limpia de la solución de DTB.
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var random =newRandom();varlist=Enumerable.Repeat(0,8).Select(x=>chars[random.Next(chars.Length)]);returnstring.Join("",list);
Después de revisar las otras respuestas y considerar los comentarios de CodeInChaos, junto con CodeInChaos aún sesgada (aunque menos), pensé en una solución final definitiva de cortar y pegar se necesitaba una . Entonces, mientras actualizaba mi respuesta, decidí hacer todo lo posible.
En relación con algunas otras respuestas: si conoce la longitud de la salida, no necesita un StringBuilder, y cuando usa ToCharArray, esto crea y llena la matriz (no necesita crear primero una matriz vacía)
En relación con algunas otras respuestas: debe usar NextBytes, en lugar de obtener una por vez para el rendimiento
Técnicamente, podría anclar la matriz de bytes para un acceso más rápido ... generalmente vale la pena cuando itera más de 6-8 veces sobre una matriz de bytes. (No hecho aquí)
Uso de RNGCryptoServiceProvider para la mejor aleatoriedad
El uso del almacenamiento en caché de un búfer de 1 MB de datos aleatorios : la evaluación comparativa muestra que la velocidad de acceso de bytes individuales en caché es ~ 1000 veces más rápida, lo que lleva 9 ms sobre 1 MB frente a 989 ms para el almacenamiento en caché.
Rechazo optimizado de la zona de sesgo dentro de mi nueva clase.
Solución final a la pregunta:
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);}
Pero necesitas mi nueva clase (no probada):
/// <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 el historial: mi solución anterior para esta respuesta, utilizaba un objeto aleatorio:
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);}
Actuación:
SecureFastRandom : primera ejecución única = ~ 9-33 ms . Imperceptible. En curso : 5 ms (a veces sube hasta 13 ms) en más de 10,000 iteraciones, con una única iteración promedio = 1.5 microsegundos.. Nota: Requiere generalmente 2, pero ocasionalmente hasta 8 actualizaciones de caché; depende de cuántos bytes individuales superen la zona de sesgo
Aleatorio : primera ejecución única = ~ 0-1 ms . Imperceptible. En curso : 5 ms en más de 10,000 iteraciones. Con una sola iteración promedio = .5 microsegundos. . Sobre la misma velocidad.
Estos enlaces son otro enfoque. El almacenamiento en búfer se podría agregar a esta nueva base de código, pero lo más importante fue explorar diferentes enfoques para eliminar el sesgo y comparar las velocidades y las ventajas y desventajas.
1) ¿Por qué todas esas constantes mágicas? Especificó la longitud de salida tres veces. Simplemente defínalo como una constante o un parámetro. Puedes usar en charSet.Lengthlugar de 62. 2) Una estática Randomsin bloqueo significa que este código no es seguro para subprocesos. 3) reducir 0-255 mod 62 introduce un sesgo detectable. 4) No se puede usar ToStringen una matriz de caracteres, que siempre regresa "System.Char[]". Necesitas usar new String(rName)en su lugar.
CodesInChaos
Gracias @CodesInChaos, nunca pensé en esas cosas en ese entonces. Todavía solo uso la clase Random, pero esto debería ser mejor. No podría pensar en una mejor manera de detectar y corregir las entradas de sesgo.
Todd
Es un poco tonto comenzar con un RNG débil ( System.Random) y luego evitar cuidadosamente cualquier sesgo en su propio código. La expresión "pulir un turd" viene a mi mente.
CodesInChaos
@CodesInChaos Y ahora el aprendiz ha superado a su maestro
Todd
4
Horrible, lo sé, pero no pude evitarlo:
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);}}}
Estaba buscando una respuesta más específica, donde quiero controlar el formato de la cadena aleatoria y encontré esta publicación. Por ejemplo: las placas (de automóviles) tienen un formato específico (por país) y quería crear placas aleatorias.
Decidí escribir mi propio método de extensión de Random para esto. (Esto es para reutilizar el mismo objeto aleatorio, ya que podría tener dobles en escenarios de subprocesos múltiples). Creé una esencia ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), pero también copiaré la clase de extensión aquí:
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 una propiedad para algo que cambia en cada acceso es bastante dudoso. Recomiendo usar un método en su lugar.
CodesInChaos
2
RNGCryptoServiceProviderdebe desecharse después de su uso.
Tsahi Asher
Solucioné el problema de IDisposable, pero esto todavía es muy dudoso, creando un nuevo RNGCryptoServiceProvider para cada letra.
piojo
@CodesInChaos hecho, ahora un método.
Matas Vaitkevicius
3
Intente combinar dos partes: única (secuencia, contador o fecha) y aleatoria
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) Puede usar literales de caracteres en lugar de los valores ASCII asociados con esos caracteres. 2) Tiene un error off-by-one en su código de coincidencia de intervalo. Necesita usar <=y en >=lugar de <y >. 3) Agregaría los paréntesis innecesarios alrededor de las &&expresiones para dejar en claro que tienen prioridad, pero, por supuesto, eso es solo una elección estilística.
CodesInChaos
+ 1 Bueno para eliminar sesgos y agregar pruebas. Sin embargo, no estoy seguro de por qué antepone su cadena aleatoria con una cadena derivada de marca de tiempo. Además, todavía se necesita deshacerse de su RNGCryptoServiceProvider
Monty
2
Una solución sin usar Random:
var chars =Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",8);var randomStr =newstring(chars.SelectMany(str => str).OrderBy(c =>Guid.NewGuid()).Take(8).ToArray());
NewGuid usa aleatoriamente internamente. Entonces esto todavía se usa al azar, solo lo está ocultando.
Wedge
2
Aquí hay una variante de la solución de Eric J, es decir, criptográficamente sólida, para WinRT (aplicación de la Tienda Windows):
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();}
Si el rendimiento es importante (especialmente cuando la longitud es alta):
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();}
Esto no es criptográficamente sólido. Hay un pequeño sesgo debido a que la operación del módulo no extiende el ancho completo de ulong por igual en 62 caracteres.
Mentira Ryan
1
Sé que esta no es la mejor manera. Pero puedes probar esto.
string str =Path.GetRandomFileName();//This method returns a random file name of 11 characters
str = str.Replace(".","");Console.WriteLine("Random string: "+ str);
¿Cómo es esa línea? Console.WriteLine ($ "Cadena aleatoria: {Path.GetRandomFileName (). Reemplazar (". "," ")}"); Es una línea.
PmanAce
1
No sé cuán criptográficamente suena esto, pero es mucho más legible y conciso que las soluciones más complejas con diferencia (imo), y debería ser más "aleatorio" que las System.Randomsoluciones basadas.
De acuerdo, no está optimizado para la velocidad, por lo que si es fundamental generar millones de cadenas aleatorias cada segundo, ¡pruebe con otra!
NOTA: Esta solución no permite la repetición de símbolos en el alfabeto, y el alfabeto DEBE ser de igual o mayor tamaño que la cadena de salida, lo que hace que este enfoque sea menos deseable en algunas circunstancias, todo depende de su caso de uso.
Si sus valores no son completamente al azar, pero de hecho pueden depender de algo, puede calcular un hash md5 o sha1 de ese 'algo' y luego truncarlo a la longitud que desee.
1) los métodos estáticos deben ser seguros para los hilos 2) ¿Cuál es el punto de incrementar el índice en lugar de usar el resultado random.Nextdirectamente? Complica el código y no logra nada útil.
CodesInChaos
0
Aquí hay un mecanismo para generar una cadena alfanumérica aleatoria (la uso para generar contraseñas y datos de prueba) sin definir el alfabeto y los números,
CleanupBase64 eliminará las partes necesarias en la cadena y seguirá agregando letras alfanuméricas aleatorias de forma recursiva.
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);}
Has declarado GenerateRandomStringy has hecho una llamada GetRandomStringdesde dentro SanitiseBase64String. También se ha declarado SanitiseBase64String y llamada CleanUpBase64Stringen GenerateRandomString.
no estoy 100% seguro, ya que no probé CADA opción aquí, pero de las que probé, esta es la más rápida. lo cronometró con cronómetro y mostró 9-10 tics, así que si la velocidad es más importante que la seguridad, intente esto:
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
clase para generar contraseñas. La siembra deRandom
tiene una entropía muy baja, por lo que no es realmente segura. Use un PRNG criptográfico para las contraseñas.Respuestas:
Escuché que LINQ es el nuevo negro, así que aquí está mi intento de usar LINQ:
(Nota: el uso de la
Random
clase hace que esto sea inadecuado para cualquier cosa relacionada con la seguridad , como crear contraseñas o tokens. Use laRNGCryptoServiceProvider
clase si necesita un generador de números aleatorios seguro).fuente
return new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
No es tan elegante como la solución Linq.
(Nota: el uso de la
Random
clase hace que esto sea inadecuado para cualquier cosa relacionada con la seguridad , como crear contraseñas o tokens. Use laRNGCryptoServiceProvider
clase si necesita un generador de números aleatorios seguro).fuente
GetRandomFileName
solución de Adam Porad es más rápida pero no permite ningún control de los caracteres utilizados y la longitud máxima posible es de 11 caracteres. LaGuid
solución de Douglas es ultrarrápida, pero los caracteres están restringidos a A-F0-9 y la longitud máxima posible es de 32 caracteres.GetRandomFileName
pero luego (a) perdería su ventaja de rendimiento y (b) su código se volvería más complicado.System.Random
No es adecuado para la seguridad.A diferencia de algunas de las alternativas presentadas, esta es criptográficamente sólida .
Basado en una discusión de alternativas aquí y actualizado / modificado según los comentarios a continuación.
Aquí hay un pequeño arnés de prueba que demuestra la distribución de caracteres en la salida anterior y actualizada. Para una discusión profunda del análisis de aleatoriedad , visite random.org.
fuente
RNGCSP
en primer lugar?) Usar mod para indexar en lachars
matriz significa que obtendrás una salida sesgada a menoschars.Length
que sea un divisor de 256.4*maxSize
bytes aleatorios y luego usarlos(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length
. También lo usaría enGetBytes
lugar deGetNonZeroBytes
. Y finalmente puedes eliminar la primera llamada aGetNonZeroBytes
. No estás usando su resultado.Solución 1: el 'rango' más grande con la longitud más flexible
Esta solución tiene más alcance que usar un GUID porque un GUID tiene un par de bits fijos que siempre son iguales y, por lo tanto, no aleatorios, por ejemplo, el carácter de 13 en hexadecimal siempre es "4", al menos en un GUID de la versión 6.
Esta solución también le permite generar una cadena de cualquier longitud.
Solución 2: una línea de código, válida para hasta 22 caracteres
No puede generar cadenas siempre que la Solución 1 y la cadena no tengan el mismo rango debido a bits fijos en los GUID, pero en muchos casos esto hará el trabajo.
Solución 3: un poco menos de código
Principalmente manteniendo esto aquí para fines históricos. Utiliza un poco menos de código, lo que sin embargo implica el gasto de tener menos rango, ya que usa hexadecimal en lugar de base64, se necesitan más caracteres para representar el mismo rango en comparación con las otras soluciones.
Lo que significa más posibilidades de colisión: probarlo con 100,000 iteraciones de 8 cadenas de caracteres generó un duplicado.
fuente
Aquí hay un ejemplo que robé del ejemplo de Sam Allen en Dot Net Perls
Si solo necesita 8 caracteres, use Path.GetRandomFileName () en el espacio de nombres System.IO. Sam dice que usar el método "Path.GetRandomFileName aquí es a veces superior, porque usa RNGCryptoServiceProvider para una mejor aleatoriedad. Sin embargo, está limitado a 11 caracteres aleatorios".
GetRandomFileName siempre devuelve una cadena de 12 caracteres con un punto en el noveno carácter. Por lo tanto, deberá eliminar el punto (ya que no es aleatorio) y luego tomar 8 caracteres de la cadena. En realidad, puedes tomar los primeros 8 caracteres y no preocuparte por el período.
PD: gracias Sam
fuente
Los objetivos principales de mi código son:
La primera propiedad se logra tomando un módulo de valor de 64 bits del tamaño del alfabeto. Para alfabetos pequeños (como los 62 caracteres de la pregunta) esto lleva a un sesgo insignificante. La segunda y tercera propiedad se logran utilizando en
RNGCryptoServiceProvider
lugar deSystem.Random
.fuente
Lo más simple:
Puede obtener un mejor rendimiento si codifica la matriz de caracteres y confía en
System.Random
:Si alguna vez le preocupa, los alfabetos en inglés pueden cambiar en algún momento y puede perder negocios, entonces puede evitar la codificación rígida, pero debería funcionar ligeramente peor (comparable al
Path.GetRandomFileName
enfoque)Los dos últimos enfoques se ven mejor si puede convertirlos en un método de extensión, por
System.Random
ejemplo.fuente
chars.Select
es muy feo ya que depende del tamaño de salida como máximo del tamaño del alfabeto.'a'.To('z')
enfoque?chars.Select()
.Take (n) `solo funciona sichars.Count >= n
. Seleccionar una secuencia que en realidad no utilizas es poco intuitiva, especialmente con esa restricción de longitud implícita. Prefiero usarEnumerable.Range
oEnumerable.Repeat
. 2) El mensaje de error "el carácter final debe ser menor que el carácter inicial" es el camino equivocado / falta anot
.chars.Count
es así> n
. Además, no entiendo la parte no intuitiva. ¿Eso hace que todos los usosTake
no sean intuitivos? No lo creo Gracias por señalar el error tipográfico.Solo algunas comparaciones de rendimiento de las diversas respuestas en este hilo:
Métodos y configuración
Resultados
Probado en LinqPad. Para un tamaño de cadena de 10, genera:
Y las cifras de rendimiento tienden a variar un poco, muy de vez en cuando
NonOptimized
en realidad es más rápido, y, a vecesForLoop
, yGenerateRandomString
el interruptor que está en la delantera.fuente
var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());
, en los que se reemplazaEachRandomizingMethod
con cada método ...Una línea de código
Membership.GeneratePassword()
hace el truco :)Aquí hay una demostración para lo mismo.
fuente
El código escrito por Eric J. es bastante descuidado (está bastante claro que es de hace 6 años ... probablemente no escribiría ese código hoy), e incluso hay algunos problemas.
No es cierto ... Hay un sesgo en la contraseña (como está escrito en un comentario),
bcdefgh
son un poco más probables que los demás (a
no lo es porqueGetNonZeroBytes
no genera bytes con un valor de cero, por lo que el sesgo porquea
está equilibrado por él), por lo que no es realmente criptográficamente sólido.Esto debería corregir todos los problemas.
fuente
También usamos cadenas personalizadas al azar, pero implementamos como ayudante de cadena, por lo que proporciona cierta flexibilidad ...
Uso
o
fuente
Mi código de una línea simple funciona para mí :)
Para expandir esto para cualquier cadena de longitud
fuente
Otra opción podría ser usar Linq y agregar caracteres aleatorios en un generador de cadenas.
fuente
Pregunta: ¿Por qué debería perder mi tiempo usando en
Enumerable.Range
lugar de escribir"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?Respuesta: Las cuerdas mágicas son MALAS. ¿ALGUIEN notó que no había "
I
" en mi cadena en la parte superior? Mi madre me enseñó a no usar cuerdas mágicas por esta misma razón ...Nota 1: como muchos otros como @dtb dijeron, no lo use
System.Random
si necesita seguridad criptográfica ...Nota 2: Esta respuesta no es la más eficiente ni la más breve, pero quería que el espacio separara la respuesta de la pregunta. El propósito de mi respuesta es más advertir contra los hilos mágicos que proporcionar una respuesta innovadora y elegante.
fuente
I
?"[A-Z0-9]
. Si, por accidente, su cadena aleatoria solo cubre[A-HJ-Z0-9]
el resultado, no cubre el rango completo permitido, lo que puede ser problemático.I
. ¿Es porque hay un personaje menos y eso hace que sea más fácil de descifrar? ¿Cuáles son las estadísticas sobre las contraseñas descifrables que contienen 35 caracteres en el rango de 36. Creo que prefiero arriesgarme ... o simplemente probar el rango de caracteres ... que incluir toda esa basura extra en mi código. Pero ese soy yo. Quiero decir, no ser un agujero en el trasero, solo digo. A veces pienso que los programadores tienen una tendencia a ir por la ruta extra compleja por el simple hecho de ser extracomplejos.I
yO
de este tipo de cadenas aleatorias para evitar que los humanos los confundan con1
y0
. Si no te importa tener una cadena legible por humanos, está bien, pero si es algo que alguien podría necesitar escribir, entonces es realmente inteligente eliminar esos caracteres.Una versión ligeramente más limpia de la solución de DTB.
Sus preferencias de estilo pueden variar.
fuente
fuente
Después de revisar las otras respuestas y considerar los comentarios de CodeInChaos, junto con CodeInChaos aún sesgada (aunque menos), pensé en una solución final definitiva de cortar y pegar se necesitaba una . Entonces, mientras actualizaba mi respuesta, decidí hacer todo lo posible.
Para obtener una versión actualizada de este código, visite el nuevo repositorio de Hg en Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Le recomiendo que copie y pegue el código de: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.fc . el botón Raw para que sea más fácil copiar y asegurarse de tener la última versión, creo que este enlace va a una versión específica del código, no a la última).
Notas actualizadas:
Solución final a la pregunta:
Pero necesitas mi nueva clase (no probada):
Para el historial: mi solución anterior para esta respuesta, utilizaba un objeto aleatorio:
Actuación:
También echa un vistazo a:
Estos enlaces son otro enfoque. El almacenamiento en búfer se podría agregar a esta nueva base de código, pero lo más importante fue explorar diferentes enfoques para eliminar el sesgo y comparar las velocidades y las ventajas y desventajas.
fuente
charSet.Length
lugar de62
. 2) Una estáticaRandom
sin bloqueo significa que este código no es seguro para subprocesos. 3) reducir 0-255 mod 62 introduce un sesgo detectable. 4) No se puede usarToString
en una matriz de caracteres, que siempre regresa"System.Char[]"
. Necesitas usarnew String(rName)
en su lugar.System.Random
) y luego evitar cuidadosamente cualquier sesgo en su propio código. La expresión "pulir un turd" viene a mi mente.Horrible, lo sé, pero no pude evitarlo:
fuente
Estaba buscando una respuesta más específica, donde quiero controlar el formato de la cadena aleatoria y encontré esta publicación. Por ejemplo: las placas (de automóviles) tienen un formato específico (por país) y quería crear placas aleatorias.
Decidí escribir mi propio método de extensión de Random para esto. (Esto es para reutilizar el mismo objeto aleatorio, ya que podría tener dobles en escenarios de subprocesos múltiples). Creé una esencia ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), pero también copiaré la clase de extensión aquí:
fuente
Ahora en sabor de una sola línea.
fuente
RNGCryptoServiceProvider
debe desecharse después de su uso.Intente combinar dos partes: única (secuencia, contador o fecha) y aleatoria
Pruebas:
fuente
<=
y en>=
lugar de<
y>
. 3) Agregaría los paréntesis innecesarios alrededor de las&&
expresiones para dejar en claro que tienen prioridad, pero, por supuesto, eso es solo una elección estilística.Una solución sin usar
Random
:fuente
Aquí hay una variante de la solución de Eric J, es decir, criptográficamente sólida, para WinRT (aplicación de la Tienda Windows):
Si el rendimiento es importante (especialmente cuando la longitud es alta):
fuente
Sé que esta no es la mejor manera. Pero puedes probar esto.
fuente
No sé cuán criptográficamente suena esto, pero es mucho más legible y conciso que las soluciones más complejas con diferencia (imo), y debería ser más "aleatorio" que las
System.Random
soluciones basadas.No puedo decidir si creo que esta versión o la siguiente es "más bonita", pero dan exactamente los mismos resultados:
De acuerdo, no está optimizado para la velocidad, por lo que si es fundamental generar millones de cadenas aleatorias cada segundo, ¡pruebe con otra!
NOTA: Esta solución no permite la repetición de símbolos en el alfabeto, y el alfabeto DEBE ser de igual o mayor tamaño que la cadena de salida, lo que hace que este enfoque sea menos deseable en algunas circunstancias, todo depende de su caso de uso.
fuente
Si sus valores no son completamente al azar, pero de hecho pueden depender de algo, puede calcular un hash md5 o sha1 de ese 'algo' y luego truncarlo a la longitud que desee.
También puede generar y truncar un guid.
fuente
fuente
random.Next
directamente? Complica el código y no logra nada útil.Aquí hay un mecanismo para generar una cadena alfanumérica aleatoria (la uso para generar contraseñas y datos de prueba) sin definir el alfabeto y los números,
CleanupBase64 eliminará las partes necesarias en la cadena y seguirá agregando letras alfanuméricas aleatorias de forma recursiva.
fuente
GenerateRandomString
y has hecho una llamadaGetRandomString
desde dentroSanitiseBase64String
. También se ha declaradoSanitiseBase64String
y llamadaCleanUpBase64String
enGenerateRandomString
.Existe uno de los increíbles paquetes nuget que lo hacen tan simple.
Uno de los buenos ejemplos está aquí .
fuente
no estoy 100% seguro, ya que no probé CADA opción aquí, pero de las que probé, esta es la más rápida. lo cronometró con cronómetro y mostró 9-10 tics, así que si la velocidad es más importante que la seguridad, intente esto:
fuente