Generazione di password casuali


229

Quando un utente sul nostro sito perde la sua password e si dirige alla pagina Password persa, dobbiamo dargli una nuova password temporanea. Non mi importa quanto sia casuale, o se corrisponde a tutte le regole di password complesse "necessarie", tutto quello che voglio fare è dare loro una password che possono cambiare in seguito.

L'applicazione è un'applicazione Web scritta in C #. quindi stavo pensando di essere cattivo e seguire la via facile per usare parte di un Guid. vale a dire

Guid.NewGuid().ToString("d").Substring(1,8)

Suggesstions? pensieri?


12
Alcune buone soluzioni qui, ma un piccolo consiglio: non generare password contenenti nessuno di questi caratteri: Oo0Ili (vedi perché) :)
stian.net

2
Ho aggiunto una risposta che utilizza KeePass come generatore di password e tra le molte opzioni esposte ho incluso anche l'opzione per escludere personaggi simili, come menzionato da @ stian.net.
Peter,

Risposte:


570

7
Non sapevo che il Framework avesse un tale metodo! Eccezionale! Sostituirò il mio codice attuale per questo!
FryHard,

35
L'ho trovato dopo aver trascorso quasi un giorno a perfezionare il mio codice pw gen. Immagine come mi sentivo;)
Rik

16
AFAIK questo metodo non genera una password conforme a una politica password sul dominio, quindi non è adatto per ogni utilizzo.
teebot,

19
Il problema principale con questa soluzione è che non puoi controllare il set di caratteri, quindi non puoi eliminare caratteri visivamente ambigui (0oOl1i! |) Che possono essere davvero importanti nella pratica.
David Hammond,

20
Qualcosa per ASP.NET Core?
Shashwat,

114
public string CreatePassword(int length)
{
        const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        StringBuilder res = new StringBuilder();
        Random rnd = new Random();
        while (0 < length--)
        {
            res.Append(valid[rnd.Next(valid.Length)]);
        }
        return res.ToString();
}

Questo ha un buon vantaggio nel poter scegliere da un elenco di caratteri disponibili per la password generata (ad es. Solo cifre, solo lettere maiuscole o solo minuscole ecc.)


2
questo metodo (base 62) è superiore al GUID (base 16) per forza: una stringa esadecimale da 8 caratteri equivale a una stringa alfanumerica da 4-5 caratteri
Jimmy

57
Randomnon è crittograficamente sicuro; System.Security.Cryptography.RNGCryptoServiceProviderè una scelta migliore.
anaximander

3
Ciò genererebbe la stessa password ogni volta che viene chiamato il metodo, poiché la classe Random viene istanziata ogni volta. Ciò potrebbe essere reso sicuro spostando Random da questo metodo e riutilizzando l'istanza.
Jon

6
No, non lo sarebbe. A meno che due persone non abbiano deciso di cambiare le password nello stesso orario.
Radu094,

10
citazione dalla domanda: non importa "se corrisponde a tutte le" necessarie "regole di password complesse" ... grazie per aver annullato il voto di questa risposta
Radu094

35

Gli obiettivi principali del mio codice sono:

  1. La distribuzione delle stringhe è quasi uniforme (non preoccuparti delle deviazioni minori, purché siano piccole)
  2. Produce più di qualche miliardo di stringhe per ogni set di argomenti. Generare una stringa di 8 caratteri (~ 47 bit di entropia) non ha senso se il tuo PRNG genera solo 2 miliardi (31 bit di entropia) di valori diversi.
  3. È sicuro, poiché mi aspetto che le persone lo utilizzino per password o altri token di sicurezza.

La prima proprietà si ottiene prendendo un valore di 64 bit modulo la dimensione dell'alfabeto. Per i piccoli alfabeti (come i 62 caratteri della domanda) questo porta a una distorsione trascurabile. La seconda e la terza proprietà si ottengono usando RNGCryptoServiceProviderinvece di System.Random.

using System;
using System.Security.Cryptography;

public static string GetRandomAlphanumericString(int length)
{
    const string alphanumericCharacters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "abcdefghijklmnopqrstuvwxyz" +
        "0123456789";
    return GetRandomString(length, alphanumericCharacters);
}

public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
    if (length < 0)
        throw new ArgumentException("length must not be negative", "length");
    if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
        throw new ArgumentException("length is too big", "length");
    if (characterSet == null)
        throw new ArgumentNullException("characterSet");
    var characterArray = characterSet.Distinct().ToArray();
    if (characterArray.Length == 0)
        throw new ArgumentException("characterSet must not be empty", "characterSet");

    var bytes = new byte[length * 8];
    new RNGCryptoServiceProvider().GetBytes(bytes);
    var result = new char[length];
    for (int i = 0; i < length; i++)
    {
        ulong value = BitConverter.ToUInt64(bytes, i * 8);
        result[i] = characterArray[value % (uint)characterArray.Length];
    }
    return new string(result);
}

(Questa è una copia della mia risposta a Come posso generare stringhe alfanumeriche di 8 caratteri casuali in C #? )


1
Se UInt64.MaxValue non è uniformemente divisibile per characterArray.Length, i caratteri selezionati casualmente non saranno distribuiti uniformemente (anche se questo sarà un effetto molto piccolo).
Jeff Walker Code Ranger

1
@JeffWalkerCodeRanger Ecco perché ho detto un pregiudizio trascurabile, non un pregiudizio. Anche con un petabyte di output hai meno dell'1% per distinguerlo da un generatore di stringhe perfettamente imparziale. L'ulteriore complessità del non-miscuglio perfetto non vale chiaramente il guadagno piuttosto teorico della casualità qui.
CodesInCos

9
Per coloro che utilizzano .NET Core, sostituire "new RNGCryptoServiceProvider (). GetBytes (bytes);" con "System.Security.Cryptography.RandomNumberGenerator.Create (). GetBytes (bytes);"
NPNelson,

24
public string GenerateToken(int length)
{
    using (RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider())
    {
        byte[] tokenBuffer = new byte[length];
        cryptRNG.GetBytes(tokenBuffer);
        return Convert.ToBase64String(tokenBuffer);
    }
}

(Potresti anche avere la classe in cui vive questo metodo implementare IDisposable, contenere un riferimento a RNGCryptoServiceProvidere smaltirlo correttamente, per evitare di crearlo ripetutamente.)

È stato notato che poiché restituisce una stringa base-64, la lunghezza dell'output è sempre un multiplo di 4, con lo spazio aggiuntivo che utilizza =come carattere di riempimento. Il lengthparametro specifica la lunghezza del buffer di byte, non la stringa di output (e quindi forse non è il nome migliore per quel parametro, ora ci penso). Questo controlla quanti byte di entropia avrà la password. Tuttavia, poiché base-64 usa un blocco di 4 caratteri per codificare ogni 3 byte di input, se chiedi una lunghezza che non sia un multiplo di 3, ci sarà un po 'di "spazio" in più, e userà= per riempire il extra.

Se non ti piace usare le stringhe di base 64 per qualsiasi motivo, puoi sostituire la Convert.ToBase64String()chiamata con una conversione in stringa normale o con uno dei Encodingmetodi; per esempio. Encoding.UTF8.GetString(tokenBuffer)- assicurati solo di scegliere un set di caratteri che possa rappresentare l'intera gamma di valori che escono dall'RNG e che produca caratteri compatibili con il luogo in cui lo invii o lo memorizzi. L'uso di Unicode, ad esempio, tende a dare molti caratteri cinesi. L'uso di base-64 garantisce un set di caratteri ampiamente compatibile e le caratteristiche di tale stringa non dovrebbero renderlo meno sicuro finché si utilizza un algoritmo di hash decente.


Penso che intendi mettere tokenBuffer dove hai LinkBuf.
PIntag

Quando uso questo codice e passo una lunghezza di 10, la stringa restituita è sempre lunga 16 caratteri e gli ultimi 2 caratteri sono sempre "==". Lo sto usando in modo errato? La lunghezza è specificata in esadecimale?
PIntag,

1
La lunghezza specificata è il numero di byte di casualità (o "entropia", come è noto tecnicamente). Tuttavia, il valore restituito è codificato in base 64, il che significa che a causa del funzionamento della codifica in base 64, la lunghezza dell'output è sempre un multiplo di 4. A volte, sono più caratteri di quanti siano necessari per codificare tutti i caratteri, quindi utilizza = caratteri per completare il resto.
anaximander,

1
RNGCryptoServiceProvider è un IDisposable, quindi lo implementerei con il modello using (ovvero utilizzando (var cryptRNG = new RNGCryptoServiceProvider ()) {...})
kloarubeek il

@kloarubeek Un punto valido e un buon suggerimento. L'ho aggiunto al mio esempio di codice.
anaximander

20

Questo è molto più grande, ma penso che appaia un po 'più completo: http://www.obviex.com/Samples/Password.aspx

///////////////////////////////////////////////////////////////////////////////
// SAMPLE: Generates random password, which complies with the strong password
//         rules and does not contain ambiguous characters.
//
// To run this sample, create a new Visual C# project using the Console
// Application template and replace the contents of the Class1.cs file with
// the code below.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// 
// Copyright (C) 2004 Obviex(TM). All rights reserved.
// 
using System;
using System.Security.Cryptography;

/// <summary>
/// This class can generate random passwords, which do not include ambiguous 
/// characters, such as I, l, and 1. The generated password will be made of
/// 7-bit ASCII symbols. Every four characters will include one lower case
/// character, one upper case character, one number, and one special symbol
/// (such as '%') in a random order. The password will always start with an
/// alpha-numeric character; it will not start with a special symbol (we do
/// this because some back-end systems do not like certain special
/// characters in the first position).
/// </summary>
public class RandomPassword
{
    // Define default min and max password lengths.
    private static int DEFAULT_MIN_PASSWORD_LENGTH  = 8;
    private static int DEFAULT_MAX_PASSWORD_LENGTH  = 10;

    // Define supported password characters divided into groups.
    // You can add (or remove) characters to (from) these groups.
    private static string PASSWORD_CHARS_LCASE  = "abcdefgijkmnopqrstwxyz";
    private static string PASSWORD_CHARS_UCASE  = "ABCDEFGHJKLMNPQRSTWXYZ";
    private static string PASSWORD_CHARS_NUMERIC= "23456789";
    private static string PASSWORD_CHARS_SPECIAL= "*$-+?_&=!%{}/";

    /// <summary>
    /// Generates a random password.
    /// </summary>
    /// <returns>
    /// Randomly generated password.
    /// </returns>
    /// <remarks>
    /// The length of the generated password will be determined at
    /// random. It will be no shorter than the minimum default and
    /// no longer than maximum default.
    /// </remarks>
    public static string Generate()
    {
        return Generate(DEFAULT_MIN_PASSWORD_LENGTH, 
                        DEFAULT_MAX_PASSWORD_LENGTH);
    }

    /// <summary>
    /// Generates a random password of the exact length.
    /// </summary>
    /// <param name="length">
    /// Exact password length.
    /// </param>
    /// <returns>
    /// Randomly generated password.
    /// </returns>
    public static string Generate(int length)
    {
        return Generate(length, length);
    }

    /// <summary>
    /// Generates a random password.
    /// </summary>
    /// <param name="minLength">
    /// Minimum password length.
    /// </param>
    /// <param name="maxLength">
    /// Maximum password length.
    /// </param>
    /// <returns>
    /// Randomly generated password.
    /// </returns>
    /// <remarks>
    /// The length of the generated password will be determined at
    /// random and it will fall with the range determined by the
    /// function parameters.
    /// </remarks>
    public static string Generate(int   minLength,
                                  int   maxLength)
    {
        // Make sure that input parameters are valid.
        if (minLength <= 0 || maxLength <= 0 || minLength > maxLength)
            return null;

        // Create a local array containing supported password characters
        // grouped by types. You can remove character groups from this
        // array, but doing so will weaken the password strength.
        char[][] charGroups = new char[][] 
        {
            PASSWORD_CHARS_LCASE.ToCharArray(),
            PASSWORD_CHARS_UCASE.ToCharArray(),
            PASSWORD_CHARS_NUMERIC.ToCharArray(),
            PASSWORD_CHARS_SPECIAL.ToCharArray()
        };

        // Use this array to track the number of unused characters in each
        // character group.
        int[] charsLeftInGroup = new int[charGroups.Length];

        // Initially, all characters in each group are not used.
        for (int i=0; i<charsLeftInGroup.Length; i++)
            charsLeftInGroup[i] = charGroups[i].Length;

        // Use this array to track (iterate through) unused character groups.
        int[] leftGroupsOrder = new int[charGroups.Length];

        // Initially, all character groups are not used.
        for (int i=0; i<leftGroupsOrder.Length; i++)
            leftGroupsOrder[i] = i;

        // Because we cannot use the default randomizer, which is based on the
        // current time (it will produce the same "random" number within a
        // second), we will use a random number generator to seed the
        // randomizer.

        // Use a 4-byte array to fill it with random bytes and convert it then
        // to an integer value.
        byte[] randomBytes = new byte[4];

        // Generate 4 random bytes.
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        rng.GetBytes(randomBytes);

        // Convert 4 bytes into a 32-bit integer value.
        int seed = BitConverter.ToInt32(randomBytes, 0);

        // Now, this is real randomization.
        Random  random  = new Random(seed);

        // This array will hold password characters.
        char[] password = null;

        // Allocate appropriate memory for the password.
        if (minLength < maxLength)
            password = new char[random.Next(minLength, maxLength+1)];
        else
            password = new char[minLength];

        // Index of the next character to be added to password.
        int nextCharIdx;

        // Index of the next character group to be processed.
        int nextGroupIdx;

        // Index which will be used to track not processed character groups.
        int nextLeftGroupsOrderIdx;

        // Index of the last non-processed character in a group.
        int lastCharIdx;

        // Index of the last non-processed group.
        int lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;

        // Generate password characters one at a time.
        for (int i=0; i<password.Length; i++)
        {
            // If only one character group remained unprocessed, process it;
            // otherwise, pick a random character group from the unprocessed
            // group list. To allow a special character to appear in the
            // first position, increment the second parameter of the Next
            // function call by one, i.e. lastLeftGroupsOrderIdx + 1.
            if (lastLeftGroupsOrderIdx == 0)
                nextLeftGroupsOrderIdx = 0;
            else
                nextLeftGroupsOrderIdx = random.Next(0, 
                                                     lastLeftGroupsOrderIdx);

            // Get the actual index of the character group, from which we will
            // pick the next character.
            nextGroupIdx = leftGroupsOrder[nextLeftGroupsOrderIdx];

            // Get the index of the last unprocessed characters in this group.
            lastCharIdx = charsLeftInGroup[nextGroupIdx] - 1;

            // If only one unprocessed character is left, pick it; otherwise,
            // get a random character from the unused character list.
            if (lastCharIdx == 0)
                nextCharIdx = 0;
            else
                nextCharIdx = random.Next(0, lastCharIdx+1);

            // Add this character to the password.
            password[i] = charGroups[nextGroupIdx][nextCharIdx];

            // If we processed the last character in this group, start over.
            if (lastCharIdx == 0)
                charsLeftInGroup[nextGroupIdx] = 
                                          charGroups[nextGroupIdx].Length;
            // There are more unprocessed characters left.
            else
            {
                // Swap processed character with the last unprocessed character
                // so that we don't pick it until we process all characters in
                // this group.
                if (lastCharIdx != nextCharIdx)
                {
                    char temp = charGroups[nextGroupIdx][lastCharIdx];
                    charGroups[nextGroupIdx][lastCharIdx] = 
                                charGroups[nextGroupIdx][nextCharIdx];
                    charGroups[nextGroupIdx][nextCharIdx] = temp;
                }
                // Decrement the number of unprocessed characters in
                // this group.
                charsLeftInGroup[nextGroupIdx]--;
            }

            // If we processed the last group, start all over.
            if (lastLeftGroupsOrderIdx == 0)
                lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;
            // There are more unprocessed groups left.
            else
            {
                // Swap processed group with the last unprocessed group
                // so that we don't pick it until we process all groups.
                if (lastLeftGroupsOrderIdx != nextLeftGroupsOrderIdx)
                {
                    int temp = leftGroupsOrder[lastLeftGroupsOrderIdx];
                    leftGroupsOrder[lastLeftGroupsOrderIdx] = 
                                leftGroupsOrder[nextLeftGroupsOrderIdx];
                    leftGroupsOrder[nextLeftGroupsOrderIdx] = temp;
                }
                // Decrement the number of unprocessed groups.
                lastLeftGroupsOrderIdx--;
            }
        }

        // Convert password characters into a string and return the result.
        return new string(password);
     }
}

/// <summary>
/// Illustrates the use of the RandomPassword class.
/// </summary>
public class RandomPasswordTest
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        // Print 100 randomly generated passwords (8-to-10 char long).
        for (int i=0; i<100; i++)
            Console.WriteLine(RandomPassword.Generate(8, 10));
    }
}
//
// END OF FILE
///////////////////////////////////////////////////////////////////////////////

2
Si scopre che esiste un supporto per questo da parte del framework. Quindi sto accettando piuttosto quella risposta!
FryHard,

1
Generare solo 2 ^ 31 password diverse, anche con dimensioni di output lunghe, è un po 'basso. Potrebbe essere sufficiente contro gli attacchi online, ma certamente troppo piccolo per gli attacchi offline. => Non lo consiglierei.
CodesInChaos,

Questa è ancora una buona risposta perché il supporto "integrato" è in realtà l'appartenenza e cosa succede se hai deciso di non utilizzare l'iscrizione ASP.NET? Funziona ancora, poiché la dipendenza è System.Web.dll, ma è un po 'imbarazzante perché il metodo non è autonomo. @GEOCHET: grazie per aver pubblicato questa alternativa.
Chris Gomez,

8

So che questo è un vecchio thread, ma ho quella che potrebbe essere una soluzione abbastanza semplice da usare per qualcuno. Facile da implementare, facile da capire e facile da validare.

Considerare il seguente requisito:

Ho bisogno di generare una password casuale che contenga almeno 2 lettere minuscole, 2 lettere maiuscole e 2 numeri. La password deve inoltre contenere almeno 8 caratteri.

La seguente espressione regolare può convalidare questo caso:

^(?=\b\w*[a-z].*[a-z]\w*\b)(?=\b\w*[A-Z].*[A-Z]\w*\b)(?=\b\w*[0-9].*[0-9]\w*\b)[a-zA-Z0-9]{8,}$

È al di fuori dello scopo di questa domanda - ma il regex si basa su lookahead / lookbehind e lookaround .

Il seguente codice creerà un set casuale di caratteri che corrispondono a questo requisito:

public static string GeneratePassword(int lowercase, int uppercase, int numerics) {
    string lowers = "abcdefghijklmnopqrstuvwxyz";
    string uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string number = "0123456789";

    Random random = new Random();

    string generated = "!";
    for (int i = 1; i <= lowercase; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            lowers[random.Next(lowers.Length - 1)].ToString()
        );

    for (int i = 1; i <= uppercase; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            uppers[random.Next(uppers.Length - 1)].ToString()
        );

    for (int i = 1; i <= numerics; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            number[random.Next(number.Length - 1)].ToString()
        );

    return generated.Replace("!", string.Empty);

}

Per soddisfare i requisiti di cui sopra, è sufficiente chiamare quanto segue:

String randomPassword = GeneratePassword(3, 3, 3);

Il codice inizia con un carattere non valido ( "!") - in modo che la stringa abbia una lunghezza in cui è possibile iniettare nuovi caratteri.

Quindi passa da 1 al numero di caratteri minuscoli richiesti e, ad ogni iterazione, prende un elemento casuale dall'elenco minuscolo e lo inietta in una posizione casuale nella stringa.

Quindi ripete il ciclo per le lettere maiuscole e per i numeri.

Ciò restituisce stringhe di lunghezza = lowercase + uppercase + numericsin cui i caratteri minuscoli, maiuscoli e numerici del conteggio desiderato sono stati inseriti in un ordine casuale.


3
Non utilizzare System.Randomper cose critiche per la sicurezza come le password. UsaRNGCryptoServiceProvider
CodesInChaos

lowers[random.Next(lowers.Length - 1)].ToString() Questo codice non genererà mai una "z". random.Next produce numeri interi inferiori al numero fornito, quindi non si deve sottrarre quello in più dalla lunghezza.
notbono

6

Per questo tipo di password, tendo a utilizzare un sistema che probabilmente genera password "usate" più facilmente. Corto, spesso costituito da frammenti pronunciabili e pochi numeri, e senza ambiguità tra i caratteri (è uno 0 o un O? A 1 o un I?). Qualcosa di simile a

string[] words = { 'bur', 'ler', 'meh', 'ree' };
string word = "";

Random rnd = new Random();
for (i = 0; i < 3; i++)
   word += words[rnd.Next(words.length)]

int numbCount = rnd.Next(4);
for (i = 0; i < numbCount; i++)
  word += (2 + rnd.Next(7)).ToString();

return word;

(Digitato direttamente nel browser, quindi utilizzare solo come linee guida. Inoltre, aggiungere più parole).


6

Non mi piacciono le password create da Membership.GeneratePassword (), poiché sono troppo brutte e hanno troppi caratteri speciali.

Questo codice genera una password non troppo brutta di 10 cifre.

string password = Guid.NewGuid().ToString("N").ToLower()
                      .Replace("1", "").Replace("o", "").Replace("0","")
                      .Substring(0,10);

Certo, potrei usare un Regex per fare tutti i rimpiazzi, ma questo è IMO più leggibile e gestibile.


2
Un GUID non dovrebbe essere abusato come
criptovaluta

3
Se utilizzerai questo metodo, puoi usare .ToString ("N") e non dovrai sostituire il "-". Non è inoltre necessario sostituire "l", poiché non è una cifra esadecimale.
JackAce,

Scopri totalmente perché l'hai fatto. Avevo solo bisogno di una password di breve durata (meno di un giorno) che non doveva essere troppo unica per utente. Tirare fuori quelli e gli zeri è un ottimo modo per eliminare la confusione. Ho anche spostato il mio in maiuscolo e poi ho ridotto la lunghezza a 6. Come anche il suggerimento "N". Grazie!
Bill Noel,

6

Ho creato questa classe che utilizza RNGCryptoServiceProvider ed è flessibile. Esempio:

var generator = new PasswordGenerator(minimumLengthPassword: 8,
                                      maximumLengthPassword: 15,
                                      minimumUpperCaseChars: 2,
                                      minimumNumericChars: 3,
                                      minimumSpecialChars: 2);
string password = generator.Generate();

È fantastico, qual è la licenza per quella classe? Posso usarlo?
codeulike,

Usalo come vuoi tu!
Alex Siepman,

3

Ho creato questo metodo simile a quello disponibile nel provider di appartenenza. Ciò è utile se non si desidera aggiungere il riferimento Web in alcune applicazioni.

Funziona benissimo.

public static string GeneratePassword(int Length, int NonAlphaNumericChars)
    {
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
        string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
        Random rd = new Random();

        if (NonAlphaNumericChars > Length || Length <= 0 || NonAlphaNumericChars < 0)
            throw new ArgumentOutOfRangeException();

            char[] pass = new char[Length];
            int[] pos = new int[Length];
            int i = 0, j = 0, temp = 0;
            bool flag = false;

            //Random the position values of the pos array for the string Pass
            while (i < Length - 1)
            {
                j = 0;
                flag = false;
                temp = rd.Next(0, Length);
                for (j = 0; j < Length; j++)
                    if (temp == pos[j])
                    {
                        flag = true;
                        j = Length;
                    }

                if (!flag)
                {
                    pos[i] = temp;
                    i++;
                }
            }

            //Random the AlphaNumericChars
            for (i = 0; i < Length - NonAlphaNumericChars; i++)
                pass[i] = allowedChars[rd.Next(0, allowedChars.Length)];

            //Random the NonAlphaNumericChars
            for (i = Length - NonAlphaNumericChars; i < Length; i++)
                pass[i] = allowedNonAlphaNum[rd.Next(0, allowedNonAlphaNum.Length)];

            //Set the sorted array values by the pos array for the rigth posistion
            char[] sorted = new char[Length];
            for (i = 0; i < Length; i++)
                sorted[i] = pass[pos[i]];

            string Pass = new String(sorted);

            return Pass;
    }

6
Non usare System.Randomper cose critiche per la sicurezza come le password. UsaRNGCryptoServiceProvider
CodesInChaos

3

Sono sempre stato molto contento del generatore di password integrato in KeePass. Dato che KeePass è un programma .Net e open source, ho deciso di scavare un po 'attorno al codice. Ho finito col riferire KeePass.exe, la copia fornita nell'installazione standard dell'applicazione, come riferimento nel mio progetto e scrivere il codice qui sotto. Puoi vedere quanto è flessibile grazie a KeePass. È possibile specificare la lunghezza, quali caratteri includere / non includere, ecc.

using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Security;


public static string GeneratePassword(int passwordLength, bool lowerCase, bool upperCase, bool digits,
        bool punctuation, bool brackets, bool specialAscii, bool excludeLookAlike)
    {
        var ps = new ProtectedString();
        var profile = new PwProfile();
        profile.CharSet = new PwCharSet();
        profile.CharSet.Clear();

        if (lowerCase)
            profile.CharSet.AddCharSet('l');
        if(upperCase)
            profile.CharSet.AddCharSet('u');
        if(digits)
            profile.CharSet.AddCharSet('d');
        if (punctuation)
            profile.CharSet.AddCharSet('p');
        if (brackets)
            profile.CharSet.AddCharSet('b');
        if (specialAscii)
            profile.CharSet.AddCharSet('s');

        profile.ExcludeLookAlike = excludeLookAlike;
        profile.Length = (uint)passwordLength;
        profile.NoRepeatingCharacters = true;

        KeePassLib.Cryptography.PasswordGenerator.PwGenerator.Generate(out ps, profile, null, _pool);

        return ps.ReadString();
    }

2
public static string GeneratePassword(int passLength) {
        var chars = "abcdefghijklmnopqrstuvwxyz@#$&ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var random = new Random();
        var result = new string(
            Enumerable.Repeat(chars, passLength)
                      .Select(s => s[random.Next(s.Length)])
                      .ToArray());
        return result;
    }

Spiega la tua risposta
Linus,

1
Questa funzione funziona molto bene con alcune modifiche. 1. Aggiunta entropia se si effettuano più chiamate contemporaneamente. Questo significa chiamato Sleep () o qualche altra entropia che causa la funzione tra le chiamate. 2. Aumenta il numero e la casualità dei caratteri sorgente. Ho creato una serie di 500 password char con keypass escludendo un gruppo di caratteri simili e altri caratteri di escape che non volevo trattare e ho usato la stringa di 2000 caratteri risultante. La casualità dopo solo 100ms di Entropy era abbastanza buona.
Wizengamot,

2

Aggiungerò un'altra risposta sconsiderata al piatto.

Ho un caso d'uso in cui ho bisogno di password casuali per la comunicazione macchina-macchina, quindi non ho alcun requisito per la leggibilità umana. Inoltre, non ho accesso al Membership.GeneratePasswordmio progetto e non voglio aggiungere la dipendenza.

Sono abbastanza sicuro che Membership.GeneratePasswordstia facendo qualcosa di simile a questo, ma qui puoi mettere a punto i pool di personaggi da cui attingere.

public static class PasswordGenerator
{
    private readonly static Random _rand = new Random();

    public static string Generate(int length = 24)
    {
        const string lower = "abcdefghijklmnopqrstuvwxyz";
        const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const string number = "1234567890";
        const string special = "!@#$%^&*_-=+";

        // Get cryptographically random sequence of bytes
        var bytes = new byte[length];
        new RNGCryptoServiceProvider().GetBytes(bytes);

        // Build up a string using random bytes and character classes
        var res = new StringBuilder();
        foreach(byte b in bytes)
        {
            // Randomly select a character class for each byte
            switch (_rand.Next(4))
            {
                // In each case use mod to project byte b to the correct range
                case 0:
                    res.Append(lower[b % lower.Count()]);
                    break;
                case 1:
                    res.Append(upper[b % upper.Count()]);
                    break;
                case 2:
                    res.Append(number[b % number.Count()]);
                    break;
                case 3:
                    res.Append(special[b % special.Count()]);
                    break;
            }
        }
        return res.ToString();
    }
}

E qualche esempio di output:

PasswordGenerator.Generate(12)
"pzY=64@-ChS$"
"BG0OsyLbYnI_"
"l9#5^2&adj_i"
"#++Ws9d$%O%X"
"IWhdIN-#&O^s"

Prevenire i reclami sull'uso di Random: La fonte primaria di casualità è ancora la crittografia RNG. Anche se si potrebbe deterministicamente foreordain la sequenza in uscita Random(dirlo prodotto solo 1) ancora non si sa il carattere successivo che sarebbe stato scelto (anche se questo potrebbe limitare la gamma di possibilità).

Un'estensione semplice sarebbe quella di aggiungere la ponderazione ai diversi set di caratteri, che potrebbe essere semplice come aumentare il valore massimo e aggiungere casi di caduta per aumentare il peso.

switch (_rand.Next(6))
{
    // Prefer letters 2:1
    case 0:
    case 1:
        res.Append(lower[b % lower.Count()]);
        break;
    case 2:
    case 3:
        res.Append(upper[b % upper.Count()]);
        break;
    case 4:
        res.Append(number[b % number.Count()]);
        break;
    case 5:
        res.Append(special[b % special.Count()]);
        break;
}

Per un generatore di password casuali più umanistico, una volta ho implementato un sistema rapido usando l'elenco di parole-dadi EFF .


1

Mi piace guardare la generazione di password, proprio come la generazione di chiavi software. Dovresti scegliere tra una serie di personaggi che seguono una buona pratica. Prendi ciò con cui @ Radu094 ha risposto e modificalo per seguire le buone pratiche. Non inserire ogni singola lettera nella matrice di caratteri. Alcune lettere sono più difficili da dire o capire al telefono.

Dovresti anche considerare l'utilizzo di un checksum sulla password che è stata generata per assicurarti che sia stata generata da te. Un buon modo per ottenere questo risultato è usare l' algoritmo LUHN .


1

Ecco cosa ho messo insieme rapidamente.

    public string GeneratePassword(int len)
    {
        string res = "";
        Random rnd = new Random();
        while (res.Length < len) res += (new Func<Random, string>((r) => {
            char c = (char)((r.Next(123) * DateTime.Now.Millisecond % 123)); 
            return (Char.IsLetterOrDigit(c)) ? c.ToString() : ""; 
        }))(rnd);
        return res;
    }

1

Uso questo codice per generare password con composizione di equilibrio di caratteri alfabetici, numerici e non alfabetici.

public static string GeneratePassword(int Length, int NonAlphaNumericChars)
    {
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
        string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
        string pass = "";
        Random rd = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < Length; i++)
        {
            if (rd.Next(1) > 0 && NonAlphaNumericChars > 0)
            {
                pass += allowedNonAlphaNum[rd.Next(allowedNonAlphaNum.Length)];
                NonAlphaNumericChars--;
            }
            else
            {
                pass += allowedChars[rd.Next(allowedChars.Length)];
            }
        }
        return pass;
    }

0

Questo è breve e funziona benissimo per me.

public static string GenerateRandomCode(int length)
{
    Random rdm = new Random();
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < length; i++)
        sb.Append(Convert.ToChar(rdm.Next(101,132)));

    return sb.ToString();
}

Potrebbe "funzionare", ma non è sicuro. Le password devono essere sicure.
CodesInChaos,

Penso che le password casuali siano password temporanee. Non vedi perché devono essere sicuri e, anche se lo fanno, puoi aggiungere numeri e caratteri speciali nell'intervallo.
user1058637

1
L'aggiunta di numeri e caratteri speciali non migliora la sicurezza se vengono generati utilizzando un PRNG prevedibile. Se sai quando è stata generata una password, puoi restringerla a pochi candidati.
Codici A Caos,

0

Sul mio sito web utilizzo questo metodo:

    //Symb array
    private const string _SymbolsAll = "~`!@#$%^&*()_+=-\\|[{]}'\";:/?.>,<";

    //Random symb
    public string GetSymbol(int Length)
    {
        Random Rand = new Random(DateTime.Now.Millisecond);
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < Length; i++)
            result.Append(_SymbolsAll[Rand.Next(0, _SymbolsAll.Length)]);
        return result.ToString();
    }

Modifica stringa _SymbolsAllper l'elenco di array.


Come già indicato nella descrizione della modifica. Se ti colleghi al tuo sito web senza che sia un riferimento al codice, stai puramente pubblicizzando il che lo rende spam, quindi rimuovi quel link dalla tua risposta.
Bowdzone,

0

Aggiunto un codice supplementare alla risposta accettata. Migliora le risposte usando solo Casuale e consente alcune opzioni di password. Mi sono piaciute anche alcune delle opzioni della risposta di KeePass, ma non volevo includere l'eseguibile nella mia soluzione.

private string RandomPassword(int length, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
    if (length < 8 || length > 128) throw new ArgumentOutOfRangeException("length");
    if (!includeCharacters && !includeNumbers && !includeNonAlphaNumericCharacters) throw new ArgumentException("RandomPassword-Key arguments all false, no values would be returned");

    string pw = "";
    do
    {
        pw += System.Web.Security.Membership.GeneratePassword(128, 25);
        pw = RemoveCharacters(pw, includeCharacters, includeNumbers, includeUppercase, includeNonAlphaNumericCharacters, includeLookAlikes);
    } while (pw.Length < length);

    return pw.Substring(0, length);
}

private string RemoveCharacters(string passwordString, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
    if (!includeCharacters)
    {
        var remove = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
        foreach (string r in remove)
        {
            passwordString = passwordString.Replace(r, string.Empty);
            passwordString = passwordString.Replace(r.ToUpper(), string.Empty);
        }
    }

    if (!includeNumbers)
    {
        var remove = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    if (!includeUppercase)
        passwordString = passwordString.ToLower();

    if (!includeNonAlphaNumericCharacters)
    {
        var remove = new string[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "}", "[", "]", "|", "\\", ":", ";", "<", ">", "/", "?", "." };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    if (!includeLookAlikes)
    {
        var remove = new string[] { "(", ")", "0", "O", "o", "1", "i", "I", "l", "|", "!", ":", ";" };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    return passwordString;
}

Questo è stato il primo link quando ho cercato di generare password casuali e quanto segue è fuori portata per la domanda attuale, ma potrebbe essere importante considerare.

  • Basato sul presupposto che System.Web.Security.Membership.GeneratePasswordè crittograficamente sicuro con un minimo del 20% dei personaggi non alfanumerici.
  • Non sono sicuro se la rimozione di caratteri e l'aggiunta di stringhe sia considerata una buona pratica in questo caso e fornisca abbastanza entropia.
  • Potrebbe voler prendere in considerazione l'implementazione in qualche modo con SecureString per l'archiviazione sicura delle password in memoria.

Cordiali saluti, non è necessario includere il file eseguibile KeyPass, in quanto è open source (il codice sorgente è disponibile per il download qui )
Alex Klaus

0

validChars può essere qualsiasi costrutto, ma ho deciso di selezionare in base agli intervalli di codice ASCII rimuovendo i caratteri di controllo. In questo esempio, è una stringa di 12 caratteri.

string validChars = String.Join("", Enumerable.Range(33, (126 - 33)).Where(i => !(new int[] { 34, 38, 39, 44, 60, 62, 96 }).Contains(i)).Select(i => { return (char)i; }));
string.Join("", Enumerable.Range(1, 12).Select(i => { return validChars[(new Random(Guid.NewGuid().GetHashCode())).Next(0, validChars.Length - 1)]; }))

0
 Generate random password of specified length with 
  - Special characters   
  - Number
  - Lowecase
  - Uppercase

  public static string CreatePassword(int length = 12)
    {
        const string lower = "abcdefghijklmnopqrstuvwxyz";
        const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const string number = "1234567890";
        const string special = "!@#$%^&*";

        var middle = length / 2;
        StringBuilder res = new StringBuilder();
        Random rnd = new Random();
        while (0 < length--)
        {
            if (middle == length)
            {
                res.Append(number[rnd.Next(number.Length)]);
            }
            else if (middle - 1 == length)
            {
                res.Append(special[rnd.Next(special.Length)]);
            }
            else
            {
                if (length % 2 == 0)
                {
                    res.Append(lower[rnd.Next(lower.Length)]);
                }
                else
                {
                    res.Append(upper[rnd.Next(upper.Length)]);
                }
            }
        }
        return res.ToString();
    }

Le risposte al codice non sono incoraggiate, in quanto non forniscono molte informazioni per i futuri lettori. Fornisci una spiegazione a ciò che hai scritto
WhatsThePoint,

Crea ripetutamente la stessa password. È necessario disporre dell'istanza di Randomstatica
trailmax,

Questa risposta genererà la stessa password se chiamata più volte di seguito !!! È necessario aggiungere Entropy tra le chiamate se si desidera utilizzare la funzione per assegnare password utilizzando il codice a più record contemporaneamente. Ancora utile però ....
Wizengamot,

0

Questo pacchetto ti consente di generare una password casuale indicando fluentemente quali caratteri deve contenere (se necessario):

https://github.com/prjseal/PasswordGenerator/

Esempio:

var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();

0

Se vuoi usare la generazione di numeri casuali crittograficamente sicura usata da System.Web.Security.Membership.GeneratePassword ma vuoi anche limitare il set di caratteri a caratteri alfanumerici, puoi filtrare il risultato con un regex:

static string GeneratePassword(int characterCount)
{
    string password = String.Empty;
    while(password.Length < characterCount)
        password += Regex.Replace(System.Web.Security.Membership.GeneratePassword(128, 0), "[^a-zA-Z0-9]", string.Empty);
    return password.Substring(0, characterCount);
}

-3
public string Sifre_Uret(int boy, int noalfa)
{

    //  01.03.2016   
    // Genel amaçlı şifre üretme fonksiyonu


    //Fonskiyon 128 den büyük olmasına izin vermiyor.
    if (boy > 128 ) { boy = 128; }
    if (noalfa > 128) { noalfa = 128; }
    if (noalfa > boy) { noalfa = boy; }


    string passch = System.Web.Security.Membership.GeneratePassword(boy, noalfa);

    //URL encoding ve Url Pass + json sorunu yaratabilecekler pass ediliyor.
    //Microsoft Garanti etmiyor. Alfa Sayısallar Olabiliyorimiş . !@#$%^&*()_-+=[{]};:<>|./?.
    //https://msdn.microsoft.com/tr-tr/library/system.web.security.membership.generatepassword(v=vs.110).aspx


    //URL ve Json ajax lar için filtreleme
    passch = passch.Replace(":", "z");
    passch = passch.Replace(";", "W");
    passch = passch.Replace("'", "t");
    passch = passch.Replace("\"", "r");
    passch = passch.Replace("/", "+");
    passch = passch.Replace("\\", "e");

    passch = passch.Replace("?", "9");
    passch = passch.Replace("&", "8");
    passch = passch.Replace("#", "D");
    passch = passch.Replace("%", "u");
    passch = passch.Replace("=", "4");
    passch = passch.Replace("~", "1");

    passch = passch.Replace("[", "2");
    passch = passch.Replace("]", "3");
    passch = passch.Replace("{", "g");
    passch = passch.Replace("}", "J");


    //passch = passch.Replace("(", "6");
    //passch = passch.Replace(")", "0");
    //passch = passch.Replace("|", "p");
    //passch = passch.Replace("@", "4");
    //passch = passch.Replace("!", "u");
    //passch = passch.Replace("$", "Z");
    //passch = passch.Replace("*", "5");
    //passch = passch.Replace("_", "a");

    passch = passch.Replace(",", "V");
    passch = passch.Replace(".", "N");
    passch = passch.Replace("+", "w");
    passch = passch.Replace("-", "7");





    return passch;



}

Potresti spiegare cosa fa il tuo codice e perché? Dalla recensione
Wai Ha Lee

È possibile che vengano eliminate solo le risposte al codice senza spiegazione.
Rook

-4

Inserisci un Timer: timer1, 2 pulsanti: button1, button2, 1 textBox: textBox1 e un comboBox: comboBox1. Assicurati di dichiarare:

int count = 0;

Codice sorgente:

 private void button1_Click(object sender, EventArgs e)
    {
    // This clears the textBox, resets the count, and starts the timer
        count = 0;
        textBox1.Clear();
        timer1.Start();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
    // This generates the password, and types it in the textBox
        count += 1;
            string possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            string psw = "";
            Random rnd = new Random { };
            psw += possible[rnd.Next(possible.Length)];
            textBox1.Text += psw;
            if (count == (comboBox1.SelectedIndex + 1))
            {
                timer1.Stop();
            }
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        // This adds password lengths to the comboBox to choose from.
        comboBox1.Items.Add("1");
        comboBox1.Items.Add("2");
        comboBox1.Items.Add("3");
        comboBox1.Items.Add("4");
        comboBox1.Items.Add("5");
        comboBox1.Items.Add("6");
        comboBox1.Items.Add("7");
        comboBox1.Items.Add("8");
        comboBox1.Items.Add("9");
        comboBox1.Items.Add("10");
        comboBox1.Items.Add("11");
        comboBox1.Items.Add("12");
    }
    private void button2_click(object sender, EventArgs e)
    {
        // This encrypts the password
        tochar = textBox1.Text;
        textBox1.Clear();
        char[] carray = tochar.ToCharArray();
        for (int i = 0; i < carray.Length; i++)
        {
            int num = Convert.ToInt32(carray[i]) + 10;
            string cvrt = Convert.ToChar(num).ToString();
            textBox1.Text += cvrt;
        }
    }

1
Non usare System.Randomper sicurezza.
CodesInChaos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.