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

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

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

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

Предложения? мысли?

Вот несколько хороших решений, но небольшой совет: не создавайте пароли, содержащие какие-либо из этих символов: Oo0Ili (вы понимаете, почему) :)

stian.net 11.06.2013 13:56

Я добавил ответ, который использует KeePass в качестве генератора паролей, и из множества представленных опций я также включил опцию для исключения похожих символов, как упоминалось @ stian.net.

Peter 14.06.2015 18:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
243
2
244 920
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

Это намного больше, но я думаю, что это выглядит немного более исчерпывающим: 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
///////////////////////////////////////////////////////////////////////////////

Оказывается, фреймворк поддерживает это. Так что я скорее принимаю этот ответ!

FryHard 11.09.2008 08:20

Создание всего 2 ^ 31 различных паролей даже при больших размерах вывода - это немного неважно. Может быть достаточно против онлайн-атак, но, конечно, слишком мало для офлайн-атак. => Я бы не рекомендовал это.

CodesInChaos 22.10.2013 12:55

Это по-прежнему хороший ответ, потому что «встроенная» поддержка - это действительно членство, а что, если вы решили не использовать членство в ASP.NET? Он по-прежнему работает, поскольку зависимость - это System.Web.dll, но это немного неудобно, потому что метод не является самодостаточным. @GEOCHET: Спасибо, что разместили эту альтернативу.

Chris Gomez 14.03.2014 05:46

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

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

этот метод (база 62) превосходит GUID (база 16) по прочности: шестнадцатеричная строка из 8 знаков эквивалентна буквенно-цифровой строке из 4-5 знаков

Jimmy 10.09.2008 22:51

Random не является криптографически безопасным; System.Security.Cryptography.RNGCryptoServiceProvider - лучший выбор.

anaximander 12.04.2013 15:20

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

Jon 29.01.2014 23:19

Нет, не пойдет. Если только два человека не решили сменить пароли в одно и то же время.

Radu094 30.01.2014 00:57

@anaximander Как бы вы заменили Random на RNGCryptoServiceProvider?

hofnarwillie 12.07.2014 03:17

См. мой ответ для простой реализации. RNGCryptoServiceProvider генерирует байты данных с высокой энтропией, поэтому вы можете просто преобразовать этот вывод в символы. Если хотите, вы можете удалить любые не буквенно-цифровые символы.

anaximander 12.07.2014 13:26

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

Wish 15.10.2014 13:28

У @Wish есть очень важный момент. Используйте эту реализацию НЕТ! Это не сработает на любой машине Windows с принудительной политикой паролей!

l33t 29.03.2016 22:40

цитата из вопроса: неважно, "соответствует ли он всем" необходимым "правилам надежных паролей ... спасибо, что проголосовали против этого ответа

Radu094 31.03.2016 01:59

Это действительно создавало для меня один и тот же пароль много раз; только 150 различных значений из 500.

ThomasRones 24.01.2019 14:59

только из-за того, как вы это тестируете: docs.microsoft.com/en-us/dotnet/api/…

Radu094 24.01.2019 16:02

Для такого рода паролей я обычно использую систему, которая может генерировать более простые «используемые» пароли. Короткие, часто состоящие из произносимых фрагментов и нескольких чисел, без двусмысленности между символами (это 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;

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

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

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

Ответ принят как подходящий

Всегда есть System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters).

Не знал, что у Framework есть такой метод! Потрясающие! Заменю на это мой текущий код!

FryHard 11.09.2008 08:19

Я нашел его, потратив почти день на совершенствование собственного кода pw gen. Представьте, как я себя чувствовал;)

Rik 13.09.2008 19:51

AFAIK этот метод не генерирует пароль, соответствующий политике паролей в домене, поэтому он не подходит для каждого использования.

teebot 14.04.2010 18:05

Это работает, даже если вы не зависели от членства в ASP.NET, но если вы решили использовать другого поставщика, это становится неудобным выбором, поскольку он частично зависит от другой конфигурации членства.

Chris Gomez 14.03.2014 05:43

Основная проблема с этим решением заключается в том, что вы не можете управлять набором символов, поэтому вы не можете устранить визуально неоднозначные символы (0oOl1i! |), Которые могут быть действительно важны на практике.

David Hammond 20.06.2014 01:16

Любой эквивалентный API для MVC 5.

vijayst 30.04.2015 05:53

Еще одна странность заключается в том, что даже когда вы устанавливаете второй параметр (numberOfNonAlphanumericCharacters) на 0, вы получаете пароль, содержащий круглые скобки и другие знаки препинания. Для меня буквенно-цифровой означает [a-zA-Z0-9].

Krisztián Balla 04.02.2016 14:51

@ JennyO'Reilly Вы правы, более информативное имя параметра было бы minimumNumberOfAlphaNumericCharacters, но это немного длинновато.

Rik 06.02.2016 14:40

Что-нибудь для ASP.NET Core?

shashwat 23.11.2016 06:20

Это работает в .Net Core или мог, но не всегда генерирует цифры, поэтому не работает ..

Lonefish 18.01.2017 19:06

@Lonefish см. Мой комментарий от 06.02.2016 выше, вероятно, та же проблема.

Rik 19.01.2017 12:57

Не совсем, я сгенерировал пароль длиной 15 и минимум 5 не буквенно-цифровых символов. Однако при первом проходе (шансы, вероятно, довольно малы, но все же) он не сгенерировал пароль с номером в нем. Так что это не удалось в Identity, так как ему нужны цифры, буквы и не буквенно-цифровые. Исправлено путем добавления числа, буквы и нечисловых символов к сгенерированному паролю, поскольку это просто заполнитель, пока человек не выберет реальный пароль (обязательно).

Lonefish 19.01.2017 13:08

А как насчет Core? Я даже не могу скомпилировать, если напишу это, и ничего не работает с использованием состояний

Piero Alberto 27.04.2018 10:26

Хотя OP заявляет, что он использует это в веб-приложении, я думаю, что это создает ненужную зависимость от библиотеки, которую можно заменить менее чем 10 строками кода.

ewahner 05.09.2018 21:35

@Lonefish Это точно не будет работать в .NET Core: github.com/PowerShell/PowerShell/issues/5352

Zenexer 18.12.2019 18:56

вы заслуживаете двух трофеев, если пропустите первый. Молодец

CelzioBR 08.01.2020 20:09

Отличный ответ для .NET Core: stackoverflow.com/a/38997554/7053420

Tristan Hudson 27.08.2020 16:56

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

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

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

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

GUID не следует использовать как крипто-ГПСЧ

CodesInChaos 08.08.2013 14:09

Если вы собираетесь использовать этот метод, вы можете использовать .ToString («N»), и вам не придется заменять «-». Также нет необходимости заменять «l», поскольку это не шестнадцатеричная цифра.

JackAce 17.03.2014 23:59

Полностью понимаю, почему вы это сделали. Мне просто нужен был недолговечный (менее суток) пароль, который не должен был быть слишком уникальным для каждого пользователя. Удаление единиц и нулей - отличный способ избавиться от путаницы. Я также просто перевел свой на верхний регистр, а затем сократил длину до 6. Как и предложение «N». Спасибо!

Bill Noel 27.02.2017 22:13

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

Отлично работает.

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

Не используйте System.Random для важных для безопасности вещей, таких как пароли. Используйте RNGCryptoServiceProvider

CodesInChaos 08.08.2013 14:04

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

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

I need a random password to be generated which has at least 2 lower-case letters, 2 upper-case letters and 2 numbers. The password must also be a minimum of 8 characters in length.

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

^(?=\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, в которые в случайном порядке помещены строчные, прописные и числовые символы нужного вам количества.

Не используйте System.Random для важных для безопасности вещей, таких как пароли. Используйте RNGCryptoServiceProvider

CodesInChaos 08.08.2013 14:04

lowers[random.Next(lowers.Length - 1)].ToString() Этот код никогда не будет генерировать букву «z». random.Next производит целые числа меньше, чем предоставленное число, поэтому вы не должны вычитать это лишнее число из длины.

notbono 08.05.2020 18:27

Вставьте 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;
        }
    }

Не используйте System.Random для безопасности.

CodesInChaos 28.09.2013 18:25

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

  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#?)

Если UInt64.MaxValue не делится равномерно на characterArray.Length, тогда случайно выбранные символы не будут равномерно распределены (хотя это будет очень незначительным эффектом).

Jeff Walker Code Ranger 19.08.2014 21:24

@JeffWalkerCodeRanger Вот почему я сказал незначительную предвзятость, а не отсутствие предвзятости. Даже с петабайтом вывода у вас есть менее 1%, чтобы отличить его от совершенно беспристрастного строкового генератора. Дополнительная сложность идеального несмещения явно не стоит здесь теоретического выигрыша в случайности.

CodesInChaos 19.08.2014 22:43

Для тех, кто использует .NET Core, замените «новый RNGCryptoServiceProvider (). GetBytes (bytes);» с "System.Security.Cryptography.RandomNumberGenerator.Create () ‌ .GetBytes (байты);"

NPNelson 31.03.2017 19:08

Это коротко, и мне он отлично подходит.

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

Это может «работать», но это, конечно, небезопасно. Пароли должны быть надежными.

CodesInChaos 06.02.2014 21:04

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

user1058637 20.03.2014 22:09

Добавление чисел и специальных символов не улучшает безопасность, если вы генерируете их с помощью предсказуемого ГПСЧ. Если вы знаете, когда был сгенерирован пароль, вы можете сузить его до нескольких кандидатов.

CodesInChaos 20.03.2014 22:15

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

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

Отлично, какая у этого класса лицензия? Могу я его использовать?

codeulike 03.08.2019 18:23

Используйте его так, как хотите!

Alex Siepman 04.08.2019 23:13

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) - просто убедитесь, что вы выбрали набор символов, который может представлять полный диапазон значений, исходящих из ГСЧ, и который создает символы, совместимые с тем, где вы его отправляете или храните. Например, при использовании Unicode появляется много китайских символов. Использование base-64 гарантирует широко совместимый набор символов, и характеристики такой строки не должны делать ее менее безопасной, если вы используете достойный алгоритм хеширования.

Я думаю, вы хотите разместить tokenBuffer там, где у вас есть linkBuf.

PIntag 18.04.2015 03:50

Когда я использую этот код и передаю длину 10, возвращаемая строка всегда имеет длину 16 символов, а последние 2 символа всегда равны «==». Я неправильно его использую? Длина указана в шестнадцатеричном формате?

PIntag 22.05.2015 03:46

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

anaximander 22.05.2015 11:39

RNGCryptoServiceProvider - это IDisposable, поэтому я бы реализовал его с использованием шаблона (т.е. используя (var cryptRNG = new RNGCryptoServiceProvider ()) {...})

kloarubeek 11.01.2020 00:30

@kloarubeek Верный момент и хорошее предложение. Я добавил это в свой образец кода.

anaximander 17.01.2020 14:55

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

    //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 для вашего списка массивов.

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

Bowdzone 30.03.2015 08:48

Я всегда был очень доволен встроенным в 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();
    }

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

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

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;



}

Не могли бы вы объяснить, что делает ваш код и почему? Из обзора

Wai Ha Lee 01.03.2016 16:16

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

Rook 01.03.2016 20:24

К принятому ответу добавлен дополнительный код. Он улучшает ответы, просто используя случайный выбор, и позволяет использовать некоторые параметры пароля. Мне также понравились некоторые варианты ответа 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 каким-либо образом для безопасного хранения паролей в памяти.

К вашему сведению, вам не нужно включать исполняемый файл KeyPass, так как он с открытым исходным кодом (исходный код доступен для загрузки здесь)

Alex Klaus 27.03.2017 07:09

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

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

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

WhatsThePoint 09.02.2018 11:58

Создает один и тот же пароль снова и снова. Необходимо иметь экземпляр Random как статический

trailmax 28.06.2018 14:51

Обратите внимание, что этот ответ будет генерировать один и тот же пароль при вызове несколько раз подряд !!! Между вызовами должна быть добавлена ​​энтропия, если вы хотите использовать функцию для назначения паролей с помощью кода сразу нескольким записям. Тем не менее, полезно ....

Wizengamot 27.07.2018 21:44

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

Пожалуйста, объясните свой ответ

Linus 25.06.2018 15:37

Эта функция работает очень хорошо с небольшими изменениями. 1. Добавлена ​​энтропия, если вы выполняете несколько вызовов одновременно. Это означает, что вызывается функция Sleep () или другая функция, вызывающая энтропию между вызовами. 2. Увеличьте количество и случайность исходных символов. Я создал серию паролей из 500 символов с keypass, исключив кучу похожих и других экранируемых символов, с которыми я не хотел иметь дело, и использовал полученную строку из 2000 символов. Случайность даже после 100 мс энтропии была довольно хорошей.

Wizengamot 27.07.2018 21:56

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

У меня есть случай использования, когда мне нужны случайные пароли для машинно-машинной связи, поэтому у меня нет требований к удобочитаемости. У меня также нет доступа к 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.

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

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

Не используйте этот ответ. Он использует обычный класс "Random", а не криптографически безопасный.

Bip901 11.11.2020 00:13

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

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

Пример:

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

Если вы хотите использовать криптографически безопасную генерацию случайных чисел, используемую 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);
}

проверьте этот код ... Я добавил .remove (length), чтобы улучшить ответ анаксимандр

 public string GeneratePassword(int length)
    {

        RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider();
        byte[] tokenBuffer = new byte[length];
        cryptRNG.GetBytes(tokenBuffer);
        return Convert.ToBase64String(tokenBuffer).Remove(length);
                  
    }

Другие вопросы по теме