Генерация случайных паролей

229

Когда пользователь на нашем сайте теряет свой пароль и отправляется на страницу «Потерянный пароль», нам нужно дать ему новый временный пароль. Я не против того, насколько это случайно, или, если оно соответствует всем «необходимым» правилам надежного пароля, все, что я хочу сделать, это дать им пароль, который они могут изменить позже.

Приложение представляет собой веб-приложение, написанное на C #. поэтому я думал о том, чтобы быть злым и идти по простому пути использования части Guid. т.е.

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

Suggesstions? мысли?

FryHard
источник
12
Несколько хороших решений, но небольшой совет: не генерируйте пароли, содержащие любой из этих символов: Oo0Ili (вы понимаете, почему) :)
stian.net
2
Я добавил ответ, который использует KeePass в качестве генератора паролей, и из множества представленных опций я также включил опцию исключения одинаковых символов, как упомянуто @ stian.net.
Питер

Ответы:

570

Там всегда System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters) .

Rik
источник
7
Не знал, что у Фреймворка есть такой метод! Потрясающие! Поменяю мой текущий код для этого!
FryHard
35
Я нашел это после того, как провел почти день, совершенствуя свой собственный код pw gen. Изображение, как я чувствовал;)
Rik
16
AFAIK этот метод не генерирует пароль, соответствующий политике паролей в домене, поэтому он не подходит для каждого использования.
Teebot
19
Основная проблема этого решения заключается в том, что вы не можете контролировать набор символов, поэтому вы не можете устранить визуально неоднозначные символы (0oOl1i! |), Что может быть очень важно на практике.
Дэвид Хаммонд
20
Что-нибудь для ASP.NET Core?
Шашват
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();
}

Это дает преимущество в том, что вы можете выбирать из списка доступных символов для сгенерированного пароля (например, только цифры, только верхний или только нижний регистр и т. Д.)

Radu094
источник
2
этот метод (база 62) превосходит GUID (база 16) по силе: шестнадцатеричная строка из 8 символов эквивалентна буквенно-цифровой строке из 4-5 символов
Джимми
57
Randomне криптографически безопасен; System.Security.Cryptography.RNGCryptoServiceProviderэто лучший выбор.
Анаксимандр
3
Это будет генерировать один и тот же пароль каждый раз, когда вызывается метод, так как каждый раз создается экземпляр класса Random. Это может быть сделано безопасным путем удаления Random из этого метода и повторного использования экземпляра.
Джон
6
Нет, не будет. Если только два человека не решили сменить пароли в одно и то же время.
Radu094
10
цитата из вопроса: не волнует, "соответствует ли он всем" необходимым "правилам надежного пароля" ... спасибо, что опровергли этот ответ
Radu094
35

Основные цели моего кода:

  1. Распределение строк практически равномерно (не обращайте внимания на незначительные отклонения, если они небольшие)
  2. Он выводит более нескольких миллиардов строк для каждого набора аргументов. Генерирование 8-символьной строки (~ 47 бит энтропии) не имеет смысла, если ваш PRNG генерирует только 2 миллиарда (31 бит энтропии) различных значений.
  3. Это безопасно, так как я ожидаю, что люди будут использовать это для паролей или других токенов безопасности.

Первое свойство достигается путем принятия 64-битного значения по модулю размера алфавита. Для маленьких алфавитов (таких как 62 символа из вопроса) это приводит к незначительному смещению. Второе и третье свойство достигается использованием RNGCryptoServiceProviderвместо 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);
}

(Это копия моего ответа на Как я могу генерировать случайные 8 буквенно-цифровые строки в C #? )

CodesInChaos
источник
1
Если UInt64.MaxValue не делится равномерно на characterArray.Length, то случайно выбранные символы не будут распределяться равномерно (хотя это будет очень небольшим эффектом).
Джефф Уокер Код Рейнджер
1
@JeffWalkerCodeRanger Вот почему я сказал, незначительное смещение, а не смещение. Даже с петабайтом вывода у вас есть менее 1%, чтобы отличить это от совершенно непредвзятого генератора строк. Дополнительная сложность идеального смещения явно не стоит здесь теоретического выигрыша в случайности.
CodesInChaos
9
Для тех, кто использует .NET Core, замените «new RNGCryptoServiceProvider (). GetBytes (bytes);» с "System.Security.Cryptography.RandomNumberGenerator.Create (). GetBytes (bytes);"
Н.П.Нельсон
24
public string GenerateToken(int length)
{
    using (RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider())
    {
        byte[] tokenBuffer = new byte[length];
        cryptRNG.GetBytes(tokenBuffer);
        return Convert.ToBase64String(tokenBuffer);
    }
}

(Вы также можете иметь класс, в котором этот метод живет, реализовать IDisposable, содержать ссылку на RNGCryptoServiceProvider и удаляющий его должным образом, чтобы избежать повторного создания его экземпляра.)

Было отмечено, что, поскольку это возвращает строку base-64, выходная длина всегда кратна 4, при этом дополнительный пробел используется =в качестве символа заполнения. lengthПараметр определяет длину байт буфера, а не выходной строки (и поэтому , возможно , не лучшее название для этого параметра, теперь я думаю об этом). Это контролирует, сколько байтов энтропии будет иметь пароль. Однако, поскольку base-64 использует 4-символьный блок для кодирования каждых 3 байтов ввода, если вы попросите длину, не кратную 3, будет некоторый дополнительный «пробел», и он будет использоваться =для заполнения дополнительно.

Если по какой-либо причине вам не нравится использование строк base-64, вы можете заменить Convert.ToBase64String()вызов либо преобразованием в обычную строку, либо любым из Encodingметодов; например. Encoding.UTF8.GetString(tokenBuffer)- просто убедитесь, что вы выбрали набор символов, который может представлять полный диапазон значений, выходящих из ГСЧ, и который создает символы, совместимые с тем, куда вы отправляете или храните это. Например, использование Юникода дает много китайских символов. Использование base-64 гарантирует широко совместимый набор символов, и характеристики такой строки не должны сделать ее менее безопасной, если вы используете приличный алгоритм хеширования.

Анаксимандр
источник
Я думаю, что вы хотите поместить tokenBuffer туда, где у вас есть linkBuf.
Пинтаг
Когда я использую этот код и передаю длину 10, возвращаемая строка всегда имеет длину 16 символов, а последние 2 символа всегда равны "==". Я использую это неправильно? Длина указана в шестнадцатеричном формате?
Пинтаг
1
Указанная длина - это количество байтов случайности (или «энтропии», как это известно технически). Однако возвращаемое значение кодируется в Base-64, что означает, что из-за того, как работает кодирование Base-64, длина вывода всегда кратна 4. Иногда это больше символов, чем необходимо для кодирования всех символов, поэтому он использует = символы для дополнения остальных.
Анаксимандр
1
RNGCryptoServiceProvider является идентификатором ID, поэтому я бы реализовал его с помощью шаблона использования (т. Е. Используя (var cryptRNG = new RNGCryptoServiceProvider ()) {...})
kloarubeek
@kloarubeek Действительная точка зрения и хорошее предложение. Я добавил это в мой пример кода.
Анаксимандр
20

Это намного больше, но я думаю, что это выглядит немного более полным: 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
///////////////////////////////////////////////////////////////////////////////
GEOCHET
источник
2
Оказывается, есть поддержка для этого структурой. Поэтому я скорее принимаю этот ответ!
FryHard
1
Генерация только 2 ^ 31 различных паролей, даже при длинных выходных размерах, немного низко. Может быть достаточно против сетевых атак, но, конечно, мало для автономных атак. => Я бы не рекомендовал это.
CodesInChaos
Это все еще хороший ответ, потому что «встроенная» поддержка - это действительно членство, а что если вы решили не использовать членство в ASP.NET? Это все еще работает, так как зависимость - System.Web.dll, но это немного неловко, потому что метод не самодостаточен. @GEOCHET: Спасибо за размещение этой альтернативы.
Крис Гомес
8

Я знаю, что это старая ветка, но у меня есть то, что может быть довольно простым решением для кого-то, чтобы использовать. Легко реализовать, легко понять и легко проверить.

Рассмотрим следующее требование:

Мне нужен случайный пароль, который должен содержать как минимум 2 буквы нижнего регистра, 2 буквы верхнего регистра и 2 цифры. Пароль также должен содержать не менее 8 символов.

Следующее регулярное выражение может проверить этот случай:

^(?=\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,}$

Это выходит за рамки этого вопроса - но регулярное выражение основано на предвкушении / предвзятости и обходных путях .

Следующий код создаст случайный набор символов, которые соответствуют этому требованию:

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

}

Чтобы выполнить вышеуказанное требование, просто позвоните по следующему номеру:

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

Код начинается с недопустимого символа ("!" ), поэтому длина строки может быть введена новыми символами.

Затем он переходит от 1 до необходимого количества символов в нижнем регистре и на каждой итерации выбирает случайный элемент из списка в нижнем регистре и вставляет его в произвольное место в строке.

Затем он повторяет цикл для прописных букв и цифр.

Это возвращает вам строки длины =, lowercase + uppercase + numericsв которые строчные, прописные и числовые символы нужного вам числа были расположены в случайном порядке.

Трой Алфорд
источник
3
Не используйте System.Randomдля безопасности важные вещи, такие как пароли. ИспользованиеRNGCryptoServiceProvider
CodesInChaos
lowers[random.Next(lowers.Length - 1)].ToString() Этот код никогда не сгенерирует «z». random.Next производит целые числа меньше, чем предоставленное число, поэтому вы не должны вычитать этот дополнительный из длины.
Нотбоно
6

Для такого рода паролей я склонен использовать систему, которая может генерировать более легко «используемые» пароли. Короткий, часто составленный из произносимых фрагментов и нескольких чисел, и без двусмысленности между символами (это 0 или O? A 1 или I?). Что-то вроде

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;

(Напечатано прямо в браузере, поэтому используйте только в качестве руководства. Также добавьте больше слов).

Адам Райт
источник
6

Мне не нравятся пароли, которые создает Membership.GeneratePassword (), так как они слишком уродливы и содержат слишком много специальных символов.

Этот код генерирует не слишком уродливый 10-значный пароль.

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

Конечно, я мог бы использовать Regex, чтобы сделать все замены, но это более читаемый и обслуживаемый IMO.

Мэтт Фреар
источник
2
GUID не должен использоваться как крипто-PRNG
CodesInChaos
3
Если вы собираетесь использовать этот метод, вы можете использовать .ToString ("N"), и вам не придется заменять "-". Также не нужно заменять «l», так как это не шестнадцатеричная цифра.
JackAce
Полностью понимаю, почему ты это сделал. Мне просто нужен был кратковременный (менее суток) пароль, который не должен был быть слишком уникальным для каждого пользователя. Вычеркивание единиц и нулей - отличный способ избавиться от путаницы. Я также переместил мой в верхний регистр и затем сократил длину до 6. Как предложение 'N' также. Спасибо!
Билл Ноэль
6

Я создал этот класс, который использует RNGCryptoServiceProvider, и он гибкий. Пример:

var generator = new PasswordGenerator(minimumLengthPassword: 8,
                                      maximumLengthPassword: 15,
                                      minimumUpperCaseChars: 2,
                                      minimumNumericChars: 3,
                                      minimumSpecialChars: 2);
string password = generator.Generate();
Алекс Сипман
источник
Это здорово, что за лицензия на этот класс? Могу ли я использовать это?
Codeulike
Используйте это так, как вы хотите!
Алекс Сипман
3

Я создал этот метод похож на доступный в членстве провайдера. Это полезно, если вы не хотите добавлять веб-ссылку в некоторых приложениях.

Работает отлично.

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
Не используйте System.Randomдля безопасности важные вещи, такие как пароли. ИспользованиеRNGCryptoServiceProvider
CodesInChaos
3

Я всегда был очень доволен встроенным в KeePass генератором паролей. Поскольку KeePass - это программа .Net с открытым исходным кодом, я решил немного покопаться в коде. В итоге я просто сослался на KeePass.exe, копию, предоставленную при стандартной установке приложения, в качестве ссылки в моем проекте и написал код ниже. Вы можете увидеть, насколько он гибок благодаря KeePass. Вы можете указать длину, какие символы включать / не включать и т. Д ...

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;
    }
Саид Ахмад
источник
Пожалуйста, объясните свой ответ
Линус
1
Эта функция работает очень хорошо с несколькими изменениями. 1. Добавлена ​​энтропия, если вы делаете несколько звонков одновременно. Это означает Sleep () или какую-то другую функцию, вызывающую энтропию между вызовами. 2. Увеличьте количество и случайность исходных символов. Я создал серию из 500 паролей символов с помощью keypass, исключая кучу похожих и других экранируемых символов, с которыми я не хотел иметь дело, и использовал полученную строку из 2000 символов. Случайность только после 100 мс Энтропии была довольно хорошей.
Визенгамот
2

Я добавлю еще один опрометчивый ответ в банк.

У меня есть случай, когда мне нужны случайные пароли для связи машина-машина, поэтому у меня нет требований к удобочитаемости. У меня также нет доступа к Membership.GeneratePasswordмоему проекту, и я не хочу добавлять зависимость.

Я совершенно уверен, Membership.GeneratePasswordчто делаю что-то похожее на это, но здесь вы можете настроить пулы персонажей для рисования.

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

И некоторые примеры вывода:

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

Для предотвращения жалоб на использование Random: Основным источником случайности по-прежнему остается крипто-ГСЧ. Даже если вы могли бы детерминировано предопределять последовательность , выходящую из Random(говорят , что это производится только 1) вы еще не знаете , следующий символ , который будет определен (хотя бы ограничить диапазон возможностей).

Одним из простых расширений было бы добавление взвешивания к различным наборам символов, которое может быть таким же простым, как повышение максимального значения и добавление падежных падежей для увеличения веса.

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

Для более гуманистического генератора случайных паролей я однажды реализовал систему подсказок, использующую список слов EFF .

kitsu.eb
источник
1

Мне нравится смотреть на генерацию паролей, как генерацию программных ключей. Вы должны выбрать из массива символов, которые следуют хорошей практике. Возьмите ответ @ Radu094 и измените его, чтобы следовать хорошей практике. Не помещайте каждую букву в массив символов. Некоторые письма сложнее сказать или понять по телефону.

Вам также следует рассмотреть возможность использования контрольной суммы для сгенерированного пароля, чтобы убедиться, что он был сгенерирован вами. Хороший способ сделать это - использовать алгоритм LUHN .

Дейл Рэйган
источник
1

Вот то, что я собрал быстро.

    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

Я использую этот код для генерации пароля с балансным составом алфавитных, числовых и не_альфа_нумеров.

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

Это коротко, и это прекрасно работает для меня.

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();
}
user1058637
источник
Это может «работать», но это, безусловно, не безопасно. Пароли должны быть безопасными.
CodesInChaos
Я думаю, что случайные пароли являются временными паролями. Не понимаю, почему они должны быть безопасными, и даже если они это делают, вы можете добавить цифры и специальные символы в диапазон.
user1058637
1
Добавление чисел и специальных символов не повышает безопасность, если вы генерируете их с использованием предсказуемого PRNG. Если вы знаете, когда был сгенерирован пароль, вы можете сузить его до нескольких кандидатов.
CodesInChaos
0

На моем сайте я использую этот метод:

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

Отредактируйте строку _SymbolsAllдля вашего списка массивов.

Grunger
источник
Как уже говорилось в описании редактирования. Если вы ссылаетесь на свой веб-сайт, не являясь ссылкой на код, вы просто рекламируете его, считая его спамом, поэтому удалите эту ссылку из своего ответа.
Боудзоне
0

Добавлен дополнительный код к принятому ответу. Он улучшает ответы только с помощью Random и позволяет использовать некоторые параметры пароля. Мне также понравились некоторые варианты ответа KeePass, но я не хотел включать исполняемый файл в мое решение.

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

Это была первая ссылка, когда я искал генерацию случайных паролей, и следующее не относится к текущему вопросу, но может быть важным для рассмотрения.

  • На основании предположения, что System.Web.Security.Membership.GeneratePasswordэто криптографически безопасно, с минимум 20% символов являются не алфавитно-цифровыми.
  • Не уверен, что удаление символов и добавление строк считается хорошей практикой в ​​этом случае и обеспечивает достаточную энтропию.
  • Возможно, стоит рассмотреть возможность реализации каким-либо образом SecureString для безопасного хранения паролей в памяти.
Matt
источник
К вашему сведению, вам не нужно включать исполняемый файл KeyPass, так как он с открытым исходным кодом (исходный код доступен для загрузки здесь )
Alex Klaus
0

validChars может быть любой конструкцией, но я решил выбрать на основе диапазонов кода ascii, удаляя контрольные символы. В этом примере это строка из 12 символов.

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();
    }
акшай тайлкар
источник
Ответы, содержащие только код, не поощряются, так как они не предоставляют много информации для будущих читателей. Пожалуйста,
дайте
Создает один и тот же пароль снова и снова. Нужно иметь экземпляр Randomкак статичный
trailmax
Обратите внимание, что этот ответ будет генерировать один и тот же пароль, если вызывается несколько раз подряд !!! Должна быть добавлена ​​энтропия между вызовами, если вы хотите использовать функцию для назначения паролей, используя код для нескольких записей одновременно. Тем не менее, все еще полезно ...
Wizengamot
0

Этот пакет позволяет вам генерировать случайный пароль, в то же время свободно указывая, какие символы он должен содержать (при необходимости):

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

Пример:

var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();
Йохан Мэйс
источник
0

Если вы хотите использовать криптографически безопасную генерацию случайных чисел, используемую System.Web.Security.Membership.GeneratePassword, но также хотите ограничить набор символов буквенно-цифровыми символами, вы можете отфильтровать результат с помощью регулярного выражения:

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);
}
samgak
источник
-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;



}
Эркан ИЛИК
источник
Не могли бы вы объяснить, что делает ваш код и почему? Из обзора
Вай Ха Ли
Ответы с кодом только без объяснения могут быть удалены.
Ладья
-4

Вставьте Timer: timer1, 2 кнопки: button1, button2, 1 textBox: textBox1 и comboBox: comboBox1. Убедитесь, что вы объявили:

int count = 0;

Исходный код:

 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
Не используйте System.Randomдля безопасности.
CodesInChaos