Gerando senhas aleatórias


229

Quando um usuário em nosso site perde sua senha e sai para a página Senha perdida, precisamos fornecer uma nova senha temporária. Eu realmente não me importo com o quão aleatório isso seja, ou se ele corresponder a todas as regras de senha forte "necessárias", tudo o que eu quero fazer é fornecer a eles uma senha que eles possam alterar posteriormente.

O aplicativo é um aplicativo da Web escrito em C #. então eu estava pensando em ser mau e seguir o caminho mais fácil de usar parte de um Guid. ie

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

Sugestões? pensamentos?


12
Algumas soluções boas aqui, mas um pouco de conselho: não gerar senhas que contenham qualquer dos seguintes caracteres: Oo0Ili (você ver por que) :)
stian.net

2
Adicionei uma resposta que usa o KeePass como gerador de senhas e, dentre as muitas opções expostas, também incluí a opção de excluir caracteres semelhantes, como mencionado em @ stian.net.
Peter Peter

Respostas:


570

7
Não sabia que o Framework tinha esse método! Impressionante! Trocarei meu código atual por isso!
FryHard 11/09/08

35
Eu o encontrei depois de passar quase um dia aperfeiçoando meu próprio código pw gen. Imagem como me senti;)
Rik

16
AFAIK, esse método não gera uma senha compatível com uma política de senha no domínio, portanto, não é adequada para todos os usos.
Teebot

19
O principal problema com esta solução é que você não pode controlar o conjunto de caracteres, portanto não pode eliminar caracteres visualmente ambíguos (0oOl1i! |), O que pode ser realmente importante na prática.
David Hammond

20
Algo para 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();
}

Isso tem um bom benefício de poder escolher em uma lista de caracteres disponíveis para a senha gerada (por exemplo, apenas dígitos, somente maiúsculas ou minúsculas etc.)


2
esse método (base 62) é superior à força do GUID (base 16): uma sequência hexadecimal de 8 caracteres é equivalente a uma alfanumérica de 4 a 5 caracteres
Jimmy

57
Randomnão é criptograficamente seguro; System.Security.Cryptography.RNGCryptoServiceProvideré uma escolha melhor.
Anaximander

3
Isso geraria a mesma senha sempre que o método for chamado, pois a classe Random é instanciada a cada vez. Isso pode ser seguro, movendo o Random para fora desse método e reutilizando a instância.
Jon

6
Não, não seria. A menos que duas pessoas decidam alterar as senhas no mesmo horário.
Radu094

10
Citação da pergunta: não me importo "se ele corresponde a todas as regras de senha fortes" necessárias "" ... obrigado por votar esta resposta embora
Radu094 30/03

35

Os principais objetivos do meu código são:

  1. A distribuição das strings é quase uniforme (não se preocupe com pequenos desvios, desde que sejam pequenos)
  2. Ele gera mais de alguns bilhões de strings para cada conjunto de argumentos. Gerar uma sequência de 8 caracteres (~ 47 bits de entropia) não faz sentido se o seu PRNG gerar apenas 2 bilhões (31 bits de entropia) de valores diferentes.
  3. É seguro, pois espero que as pessoas usem isso para senhas ou outros tokens de segurança.

A primeira propriedade é obtida assumindo um módulo de valor de 64 bits no tamanho do alfabeto. Para alfabetos pequenos (como os 62 caracteres da pergunta), isso leva a um viés desprezível. A segunda e a terceira propriedade são obtidas usando em RNGCryptoServiceProvidervez de System.Random.

using System;
using System.Security.Cryptography;

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);
}

(Esta é uma cópia da minha resposta para Como gerar seqüências alfanuméricas aleatórias de 8 caracteres em C #? )


1
Se UInt64.MaxValue não for divisível igualmente por characterArray.Length, os caracteres selecionados aleatoriamente não serão distribuídos igualmente (embora isso seja um efeito muito pequeno).
Jeff Walker Código ranger

1
@JeffWalkerCodeRanger Foi por isso que eu disse um viés desprezível, não um viés. Mesmo com um petabyte de saída, você tem menos de 1% para diferenciá-lo de um gerador de strings perfeitamente imparcial. A complexidade adicional de um desatamento perfeito não vale claramente o ganho teórico em aleatoriedade aqui.
CodesInChaos

9
Para aqueles que usam o .NET Core, substitua "new RNGCryptoServiceProvider (). GetBytes (bytes);" com "System.Security.Cryptography.RandomNumberGenerator.Create (). GetBytes (bytes);"
NPNelson 31/03

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

(Você também pode fazer com que a classe onde esse método mora implemente IDisposable, mantenha uma referência RNGCryptoServiceProvidere descarte-a adequadamente, para evitar instanciações repetidas.)

Observou-se que, como isso retorna uma string de base 64, o comprimento da saída é sempre um múltiplo de 4, com o espaço extra sendo usado =como caractere de preenchimento. O lengthparâmetro especifica o comprimento do buffer de bytes, não a sequência de saída (e, portanto, talvez não seja o melhor nome para esse parâmetro, agora penso nisso). Isso controla quantos bytes de entropia a senha terá. No entanto, como base-64 usa um bloco de 4 caracteres para codificar cada 3 bytes de entrada, se você solicitar um comprimento que não seja múltiplo de 3, haverá algum "espaço" extra, que será usado =para preencher o extra.

Se você não gostar de usar cadeias de base 64 por qualquer motivo, poderá substituir a Convert.ToBase64String()chamada por uma conversão para uma cadeia regular ou por qualquer um dos Encodingmétodos; por exemplo. Encoding.UTF8.GetString(tokenBuffer)- apenas certifique-se de escolher um conjunto de caracteres que possa representar toda a gama de valores que sai do RNG e que produz caracteres compatíveis com onde quer que você esteja enviando ou armazenando isso. O uso do Unicode, por exemplo, tende a fornecer muitos caracteres chineses. O uso da base-64 garante um conjunto de caracteres amplamente compatível, e as características dessa string não devem torná-la menos segura, desde que você use um algoritmo de hash decente.


Eu acho que você pretende colocar tokenBuffer onde você tem linkBuf.
PIntag

Quando eu uso esse código e passo 10, a string retornada sempre tem 16 caracteres e os 2 caracteres finais são sempre "==". Estou usando incorretamente? O comprimento especificado em hexadecimal?
PIntag

1
O comprimento especificado é o número de bytes de aleatoriedade (ou "entropia", como é conhecido tecnicamente). No entanto, o valor retornado é codificado em base 64, o que significa que, devido ao funcionamento da codificação em base 64, o comprimento da saída é sempre um múltiplo de 4. Às vezes, há mais caracteres do que o necessário para codificar todos os caracteres, portanto, ele usa = caracteres para preencher o resto.
Anaximander

1
RNGCryptoServiceProvider é um IDisposable, então eu o implementaria com o padrão de uso (ou seja, usando (var cryptRNG = new RNGCryptoServiceProvider ()) {...})
kloarubeek em

@kloarubeek Um ponto válido e uma boa sugestão. Eu adicionei isso ao meu exemplo de código.
anaximander 17/01

20

Isso é muito maior, mas acho que parece um pouco mais abrangente: 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
Acontece que há suporte para isso pela estrutura. Então, estou aceitando essa resposta!
FryHard 11/09/08

1
Gerar apenas 2 ^ 31 senhas diferentes, mesmo com tamanhos de saída longos, é um pouco ruim. Pode ser suficiente contra ataques online, mas certamente pequeno demais para ataques offline. => Eu não recomendaria isso.
CodesInChaos

Essa ainda é uma boa resposta, porque o suporte "interno" é realmente Associação e se você decidiu não usar a Associação ASP.NET? Ainda funciona, já que a dependência é System.Web.dll, mas é um pouco estranho porque o método não é autônomo. @GEOCHET: Obrigado por postar esta alternativa.
Chris Gomez

8

Sei que esse é um tópico antigo, mas tenho o que pode ser uma solução bastante simples para alguém usar. Fácil de implementar, fácil de entender e fácil de validar.

Considere o seguinte requisito:

Preciso que seja gerada uma senha aleatória que tenha pelo menos duas letras minúsculas, duas maiúsculas e dois números. A senha também deve ter no mínimo 8 caracteres.

A seguinte expressão regular pode validar este 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,}$

Está fora do escopo desta pergunta - mas o regex é baseado em lookahead / lookbehind e lookaround .

O código a seguir criará um conjunto aleatório de caracteres que corresponde a esse 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);

}

Para atender ao requisito acima, basta ligar para o seguinte:

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

O código começa com um caractere inválido ( "!") - para que a string tenha um comprimento no qual novos caracteres possam ser injetados.

Em seguida, faz o loop de 1 até o número de caracteres em minúsculas necessário e, em cada iteração, pega um item aleatório da lista em minúsculas e o injeta em um local aleatório na string.

Em seguida, repete o loop para letras maiúsculas e para números.

Isso retorna as seqüências de comprimento = lowercase + uppercase + numericsem que caracteres minúsculos, maiúsculos e numéricos da contagem que você deseja foram colocados em uma ordem aleatória.


3
Não use System.Randompara itens críticos de segurança, como senhas. UseRNGCryptoServiceProvider
CodesInChaos

lowers[random.Next(lowers.Length - 1)].ToString() Este código nunca irá gerar um 'z'. random.Next produz números inteiros menores que o número fornecido, portanto você não deve subtrair esse número extra do comprimento.
notbono

6

Para esse tipo de senha, costumo usar um sistema que provavelmente gera senhas "usadas" mais facilmente. Curto, geralmente composto de fragmentos pronunciáveis ​​e alguns números e sem ambiguidade entre caracteres (é 0 ou 0? A 1 ou I?). Algo como

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;

(Digitado diretamente no navegador, use apenas como diretrizes. Além disso, adicione mais palavras).


6

Não gosto das senhas criadas por Membership.GeneratePassword (), pois são muito feias e têm muitos caracteres especiais.

Esse código gera uma senha não muito feia de 10 dígitos.

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

Claro, eu poderia usar um Regex para fazer todas as substituições, mas isso é mais IMO legível e sustentável.


2
Um GUID não deve ser abusado como criptografia PRNG
CodesInChaos

3
Se você usar esse método, poderá usar .ToString ("N") e não precisará substituir o "-". Também não há necessidade de substituir "l", pois não é um dígito hexadecimal.
21414 JackAce

Veja totalmente por que você fez isso. Eu só precisava de uma senha de vida curta (menos de um dia) que não precisava ser muito exclusiva por usuário. Arrancar os zeros e é uma ótima maneira de eliminar a confusão. Também mudei a minha para maiúscula e depois reduzi o comprimento para 6. Como a sugestão 'N' também. Obrigado!
Bill Noel

6

Criei essa classe que usa RNGCryptoServiceProvider e é flexível. Exemplo:

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

Isso é ótimo, qual é a licença dessa classe? Posso usá-lo?
precisa saber é o seguinte

Use-o como quiser!
Alex Siepman 4/08/19

3

Criei esse método semelhante ao disponível no provedor de associação. Isso é útil se você não quiser adicionar a referência da web em alguns aplicativos.

Isso funciona muito bem.

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
Não use System.Randompara itens críticos de segurança, como senhas. UseRNGCryptoServiceProvider
CodesInChaos

3

Eu sempre fiquei muito feliz com o gerador de senhas embutido no KeePass. Como o KeePass é um programa .Net e código aberto, decidi pesquisar um pouco o código. Acabei referenciando o KeePass.exe, a cópia fornecida na instalação padrão do aplicativo, como referência no meu projeto e escrevendo o código abaixo. Você pode ver o quão flexível é graças ao KeePass. Você pode especificar o comprimento, quais caracteres incluir / não incluir, etc ...

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;
    }

Por favor, explique sua resposta
Linus

1
Esta função funciona muito bem com algumas alterações. 1. Entropia adicionada se você estiver fazendo várias chamadas ao mesmo tempo. Isso significa chamado Sleep () ou alguma outra entropia causando função entre as chamadas. 2. Aumente o número e a aleatoriedade dos caracteres de origem. Eu criei uma série de 500 senhas char com keypass, excluindo um monte de caracteres semelhantes e outros caracteres escapáveis ​​com os quais não queria lidar e usei a sequência de caracteres de 2000 resultante. A aleatoriedade após apenas 100ms de Entropy foi muito boa.
Wizengamot

2

Vou adicionar outra resposta mal aconselhada ao pote.

Eu tenho um caso de uso em que preciso de senhas aleatórias para comunicação máquina-máquina, portanto, não tenho nenhum requisito de legibilidade humana. Também não tenho acesso ao Membership.GeneratePasswordmeu projeto e não quero adicionar a dependência.

Estou bastante certo de que Membership.GeneratePasswordestá fazendo algo semelhante a isso, mas aqui você pode ajustar os grupos de caracteres para desenhar.

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 algum exemplo de saída:

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

Para evitar queixas sobre o uso de Random: A principal fonte de aleatoriedade ainda é o RNG criptográfico. Mesmo se você pudesse deterministically preordenar a seqüência saindo de Random(dizem que só produziu 1), você ainda não sabe o próximo caractere que seria escolhido (embora isso iria limitar o leque de possibilidades).

Uma extensão simples seria adicionar ponderação aos diferentes conjuntos de caracteres, o que poderia ser tão simples quanto aumentar o valor máximo e adicionar casos de queda para aumentar o 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;
}

Para um gerador de senhas aleatórias mais humanístico, uma vez implementei um sistema de prompt usando a lista de dados e palavras da EFF .


1

Eu gosto de olhar para gerar senhas, assim como gerar chaves de software. Você deve escolher entre uma variedade de caracteres que seguem uma boa prática. Pegue o que o Radu094 respondeu e modifique-o para seguir as boas práticas. Não coloque todas as letras na matriz de caracteres. Algumas letras são mais difíceis de dizer ou entender por telefone.

Você também deve considerar o uso de uma soma de verificação na senha que foi gerada para garantir que ela foi gerada por você. Uma boa maneira de conseguir isso é usar o algoritmo LUHN .


1

Aqui está o que eu montei 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

Eu uso esse código para gerar senha com composição de saldo de caracteres alfabéticos, caracteres numéricos e não_alfa_numéricos.

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

Isso é curto e funciona muito bem para mim.

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();
}

Pode "funcionar", mas certamente não é seguro. As senhas precisam ser seguras.
CodesInChaos

Eu acho que senhas aleatórias são senhas temporárias. Não perceba por que eles precisam ser seguros e, mesmo se houver, você pode adicionar números e caracteres especiais no intervalo.
user1058637

1
Adicionar números e caracteres especiais não melhora a segurança se você os gerar usando um PRNG previsível. Se você souber quando uma senha foi gerada, poderá reduzi-la a apenas alguns candidatos.
CodesInChaos

0

No meu site, eu uso este método:

    //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();
    }

Edite a string _SymbolsAllpara sua lista de matrizes.


Como já indicado na descrição da edição. Se você criar um link para o seu site sem que seja uma referência de código, estará publicitando apenas, o que o torna spam. Remova o link da sua resposta.
Bowdzone

0

Adicionado algum código suplementar à resposta aceita. Ele melhora as respostas apenas usando o Random e permite algumas opções de senha. Também gostei de algumas das opções da resposta do KeePass, mas não quis incluir o executável na minha solução.

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;
}

Esse foi o primeiro link quando procurei gerar senhas aleatórias e o seguinte não está no escopo da pergunta atual, mas pode ser importante considerar.

  • Com base no pressuposto de que System.Web.Security.Membership.GeneratePasswordé criptograficamente seguro, com um mínimo de 20% dos caracteres não alfanuméricos.
  • Não tenho certeza se remover caracteres e anexar cadeias é considerado uma boa prática neste caso e fornece entropia suficiente.
  • Pode-se considerar a implementação de alguma forma com o SecureString para armazenamento seguro de senhas na memória.

FYI, você não precisa incluir o arquivo executável KeyPass, como é open source (código-fonte está disponível para download aqui )
Alex Klaus

0

validChars pode ser qualquer construção, mas decidi selecionar com base nos intervalos de código ascii removendo os caracteres de controle. Neste exemplo, é uma cadeia de 12 caracteres.

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();
    }

Código únicas respostas Arent incentivado como eles não fornecem muita informação para futuros leitores, fornecer uma explicação para o que você escreveu
WhatsThePoint

Cria a mesma senha repetidamente. Necessidade de ter exemplo de Randomcomo estático
TRAILMAX

Observe que esta resposta irá gerar a mesma senha se for chamada várias vezes seguidas !!! É necessário adicionar entropia entre as chamadas se você desejar usar a função para atribuir senhas usando o código a vários registros de uma só vez. Ainda é útil ...
Wizengamot

0

Este pacote permite gerar uma senha aleatória enquanto indica fluentemente quais caracteres ela deve conter (se necessário):

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

Exemplo:

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

0

Se você deseja usar a geração de números aleatórios criptograficamente segura usada pelo System.Web.Security.Membership.GeneratePassword, mas também deseja restringir o conjunto de caracteres a caracteres alfanuméricos, é possível filtrar o resultado com uma 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;



}

Você poderia explicar o que seu código faz e por quê? Da avaliação
Wai Ha Lee

Respostas apenas de código sem explicação provavelmente serão excluídas.
Rook

-4

Insira um Timer: timer1, 2 botões: button1, button2, 1 textBox: textBox1 e um comboBox: comboBox1. Certifique-se de declarar:

int count = 0;

Código fonte:

 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
Não use System.Randompor segurança.
CodesInChaos
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.