c# - ruleta - numeros al azar
Generación única de cadenas aleatorias (12)
Advertiría que los GUID no son números aleatorios . No deben usarse como base para generar cualquier cosa que espere que sea totalmente aleatoria (consulte http://en.wikipedia.org/wiki/Globally_Unique_Identifier ):
El criptoanálisis del generador de GUID de WinAPI muestra que, dado que la secuencia de GUID de V4 es pseudoaleatoria, dado el estado inicial, se pueden predecir hasta los próximos 250 000 GUID devueltos por la función UuidCreate. Esta es la razón por la que los GUID no deben usarse en criptografía, por ejemplo, como claves aleatorias.
En su lugar, solo usa el método aleatorio C #. Algo como esto ( código que se encuentra aquí ):
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch ;
for(int i=0; i<size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
builder.Append(ch);
}
return builder.ToString();
}
Los GUID están bien si quieres algo único (como un nombre de archivo único o clave en una base de datos), pero no son buenos para algo que quieres que sea aleatorio (como una contraseña o clave de cifrado). Entonces depende de tu aplicación.
Editar . Microsoft dice que Random tampoco es tan bueno ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ):
Para generar un número aleatorio criptográficamente seguro adecuado para crear una contraseña aleatoria, por ejemplo, use una clase derivada de System.Security.Cryptography.RandomNumberGenerator como System.Security.Cryptography.RNGCryptoServiceProvider.
Me gustaría generar cadenas únicas aleatorias como las que genera la biblioteca MSDN:
http://msdn.microsoft.com/en-us/library/t9zk6eay.aspx , por ejemplo. Se debería generar una cadena como ''t9zk6eay''.
Esto funciona perfecto para mi
private string GeneratePasswordResetToken()
{
string token = Guid.NewGuid().ToString();
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(token);
return Convert.ToBase64String(plainTextBytes);
}
Esto se ha pedido para varios idiomas. Aquí hay una pregunta sobre las contraseñas que también debería ser aplicable aquí.
Si desea utilizar las cadenas para el acortamiento de URL, también necesitará un Dictionary <> o verificación de base de datos para ver si ya se ha utilizado una ID generada.
No creo que realmente sean aleatorios, pero supongo que son algunos hashes.
Cada vez que necesito un identificador aleatorio, suelo usar un GUID y convertirlo a su representación "desnuda":
Guid.NewGuid().ToString("n");
Si desea cadenas alfanuméricas con caracteres en minúsculas y mayúsculas ([a-zA-Z0-9]), puede usar Convert.ToBase64String () para una solución rápida y sencilla.
En cuanto a la singularidad, revise el problema del cumpleaños para calcular la probabilidad de una colisión (A) la longitud de las cadenas generadas y (B) la cantidad de cadenas generadas.
Random random = new Random();
int outputLength = 10;
int byteLength = (int)Math.Ceiling(3f / 4f * outputLength); // Base64 uses 4 characters for every 3 bytes of data; so in random bytes we need only 3/4 of the desired length
byte[] randomBytes = new byte[byteLength];
string output;
do
{
random.NextBytes(randomBytes); // Fill bytes with random data
output = Convert.ToBase64String(randomBytes); // Convert to base64
output = output.Substring(0, outputLength); // Truncate any superfluous characters and/or padding
} while (output.Contains(''/'') || output.Contains(''+'')); // Repeat if we contain non-alphanumeric characters (~25% chance if length=10; ~50% chance if length=20; ~35% chance if length=32)
Simplifiqué la solución @Michael Kropats e hice una versión LINQ-esque.
string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
{
var outOfRange = byte.MaxValue + 1 - (byte.MaxValue + 1) % alphabet.Length;
return string.Concat(
Enumerable
.Repeat(0, int.MaxValue)
.Select(e => RandomByte())
.Where(randomByte => randomByte < outOfRange)
.Take(length)
.Select(randomByte => alphabet[randomByte % alphabet.Length])
);
}
byte RandomByte()
{
using (var randomizationProvider = new RNGCryptoServiceProvider())
{
var randomBytes = new byte[1];
randomizationProvider.GetBytes(randomBytes);
return randomBytes.Single();
}
}
Solución de Michael Kropats en VB.net
Private Function RandomString(ByVal length As Integer, Optional ByVal allowedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") As String
If length < 0 Then Throw New ArgumentOutOfRangeException("length", "length cannot be less than zero.")
If String.IsNullOrEmpty(allowedChars) Then Throw New ArgumentException("allowedChars may not be empty.")
Dim byteSize As Integer = 256
Dim hash As HashSet(Of Char) = New HashSet(Of Char)(allowedChars)
''Dim hash As HashSet(Of String) = New HashSet(Of String)(allowedChars)
Dim allowedCharSet() = hash.ToArray
If byteSize < allowedCharSet.Length Then Throw New ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize))
'' Guid.NewGuid and System.Random are not particularly random. By using a
'' cryptographically-secure random number generator, the caller is always
'' protected, regardless of use.
Dim rng = New System.Security.Cryptography.RNGCryptoServiceProvider()
Dim result = New System.Text.StringBuilder()
Dim buf = New Byte(128) {}
While result.Length < length
rng.GetBytes(buf)
Dim i
For i = 0 To buf.Length - 1 Step +1
If result.Length >= length Then Exit For
'' Divide the byte into allowedCharSet-sized groups. If the
'' random value falls into the last group and the last group is
'' too small to choose from the entire allowedCharSet, ignore
'' the value in order to avoid biasing the result.
Dim outOfRangeStart = byteSize - (byteSize Mod allowedCharSet.Length)
If outOfRangeStart <= buf(i) Then
Continue For
End If
result.Append(allowedCharSet(buf(i) Mod allowedCharSet.Length))
Next
End While
Return result.ToString()
End Function
Usar Guid sería una buena manera, pero para obtener algo que se parezca a tu ejemplo, probablemente quieras convertirlo en una cadena Base64:
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=","");
GuidString = GuidString.Replace("+","");
Me deshago de "=" y "+" para acercarme un poco más a tu ejemplo, de lo contrario obtienes "==" al final de la cadena y un "+" en el medio. Aquí hay una cadena de salida de ejemplo:
"OZVV5TpP4U6wJthaCORZEQ"
Obtenga una clave única con el código GUID Hash
public static string GetUniqueKey(int length)
{
string guidResult = string.Empty;
while (guidResult.Length < length)
{
// Get the GUID.
guidResult += Guid.NewGuid().ToString().GetHashCode().ToString("x");
}
// Make sure length is valid.
if (length <= 0 || length > guidResult.Length)
throw new ArgumentException("Length must be between 1 and " + guidResult.Length);
// Return the first length bytes.
return guidResult.Substring(0, length);
}
Actualización 2016/1/23
Si esta respuesta te resulta útil, te puede interesar una biblioteca de generación de contraseñas sencilla (~ 500 SLOC) que publiqué :
Install-Package MlkPwgen
Luego puede generar cadenas aleatorias como en la respuesta a continuación:
var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
Una ventaja de la biblioteca es que el código se tiene en cuenta mejor, por lo que puede usar aleatoriedad segura para algo más que generar cadenas . Visite el sitio del proyecto para más detalles.
Respuesta original
Como nadie ha proporcionado un código de seguridad, publico lo siguiente en caso de que alguien lo encuentre útil.
string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
if (string.IsNullOrEmpty(allowedChars)) throw new ArgumentException("allowedChars may not be empty.");
const int byteSize = 0x100;
var allowedCharSet = new HashSet<char>(allowedChars).ToArray();
if (byteSize < allowedCharSet.Length) throw new ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize));
// Guid.NewGuid and System.Random are not particularly random. By using a
// cryptographically-secure random number generator, the caller is always
// protected, regardless of use.
using (var rng = new System.Security.Cryptography.RandomNumberGenerator.Create()) {
var result = new StringBuilder();
var buf = new byte[128];
while (result.Length < length) {
rng.GetBytes(buf);
for (var i = 0; i < buf.Length && result.Length < length; ++i) {
// Divide the byte into allowedCharSet-sized groups. If the
// random value falls into the last group and the last group is
// too small to choose from the entire allowedCharSet, ignore
// the value in order to avoid biasing the result.
var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);
if (outOfRangeStart <= buf[i]) continue;
result.Append(allowedCharSet[buf[i] % allowedCharSet.Length]);
}
}
return result.ToString();
}
}
Gracias a Ahmad por señalar cómo hacer que el código funcione en .NET Core.
Pruebe la combinación entre Guid y Time.Ticks
var randomNumber = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + DateTime.Now.Ticks;
randomNumber = System.Text.RegularExpressions.Regex.Replace(randomNumber, "[^0-9a-zA-Z]+", "");
- no estoy seguro de que el enlace de Microsoft se genere al azar
- eche un vistazo al nuevo Guid (). ToString ()