Генерування випадкових паролів


229

Коли користувач на нашому сайті втрачає свій пароль і переходить на сторінку «Забули пароль», нам потрібно надати йому новий тимчасовий пароль. Я не дуже заперечую, наскільки це випадково, або якщо він відповідає всім «потрібним» сильним правилам паролів, все, що я хочу зробити, - це дати їм пароль, який вони можуть змінити пізніше.

Додаток - це веб-додаток, написане на C #. тож я думав бути підлим і йти по простому маршруту використання частини Посібника. тобто

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

Пропозиції? думки?


12
Тут є кілька хороших рішень, але невелика порада: не створюйте паролі, що містять жоден із цих символів: Oo0Ili (ви розумієте, чому) :)
stian.net

2
Я додав відповідь, що використовує KeePass як генератор паролів, і з багатьох відкритих варіантів я також включив можливість виключення схожих символів, як згадує @ stian.net.
Пітер

Відповіді:


570

7
Не знав, що в Рамці є такий метод! Дивовижно! Буде поміняти мій поточний код для цього!
FryHard

35
Я знайшов це, витративши майже день на вдосконалення власного ген-коду pw. Зображення, як я себе почував;)
Рік

16
AFAIK цей метод не генерує пароль, що відповідає політиці паролів у домені, тому він не підходить для кожного використання.
teebot

19
Основна проблема цього рішення полягає в тому, що ви не можете керувати набором символів, тому ви не можете усунути візуально неоднозначні символи (0oOl1i! |), Що може бути дуже важливим на практиці.
Девід Хаммонд

20
Що для чого ASP.NET Core?
shashwat

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

Це має добру перевагу в тому, що ви можете вибрати зі списку доступних символів для згенерованого пароля (наприклад, лише цифри, лише великі регістри або лише малі регістри тощо)


2
цей метод (база 62) за силою перевершує GUID (основа 16): шістнадцятигранна шістнадцяткова струна еквівалентна буквено-цифровій 4-5 знаків
Джиммі

57
Randomне є криптографічно захищеним; System.Security.Cryptography.RNGCryptoServiceProvider- кращий вибір.
anaximander

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


1
Якщо UInt64.MaxValue не поділяється рівним символомArray.Length, то випадково вибрані символи не будуть розподілені рівномірно (хоча це буде дуже малим ефектом).
Код Джеффа Уокера Ranger Code

1
@JeffWalkerCodeRanger Ось чому я сказав незначні упередження, а не ніякі упередження. Навіть при петабайт виводу у вас менше 1%, щоб відрізнити це від ідеально неупередженого генератора струн. Додаткова складність бездоганного незміщення, очевидно, не вартий досить теоретичної вигоди у випадковості.
CodesInChaos

9
Для тих, хто використовує .NET Core, замініть "новий RNGCryptoServiceProvider (). GetBytes (bytes);" з "System.Security.Cryptography.RandomNumberGenerator.Create (). GetBytes (bytes);"
NPNelson

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

(Ви також можете мати клас, в якому цей метод життя реалізує IDisposable, мати посилання на RNGCryptoServiceProvider та розпоряджатися ним належним чином, щоб уникнути повторної інстанції.)

Помічено, що оскільки це повертає рядок base-64, довжина виводу завжди кратна 4, при цьому додатковий простір використовується =як символ прокладки. lengthПараметр визначає довжину байт буфера, а НЕ вихідний рядки (і тому , можливо , не найкращий назву для цього параметра, тепер я думаю про це). Це контролює кількість байтів ентропії пароля. Однак, оскільки base-64 використовує 4-символьний блок для кодування кожного 3-х байт введення, якщо ви запитаєте довжину, не кратну 3, буде додатковий "простір", і він буде використовувати= для заповнення додатково.

Якщо з будь-якої причини вам не подобається використовувати рядки base-64, ви можете замінити Convert.ToBase64String()виклик або перетворенням у звичайний рядок, або будь-яким із Encodingметодів; напр.Encoding.UTF8.GetString(tokenBuffer)- просто переконайтеся, що ви вибрали набір символів, який може представляти весь діапазон значень, що виходять з RNG, і видає символи, сумісні з тим, куди ви надсилаєте або зберігаєте. Наприклад, використання Unicode, як правило, дає багато китайських символів. Використання base-64 гарантує широко сумісний набір символів, і характеристики такого рядка не повинні робити його менш захищеним, якщо ви використовуєте гідний алгоритм хешування.


Я думаю, ти маєш на увазі поставити tokenBuffer там, де у тебе є посиланняBuf.
PIntag

Коли я використовую цей код і пропускаю довжиною 10, повертається рядок завжди має 16 символів, а останні 2 символи завжди "==". Чи неправильно я його використовую? Чи вказана довжина в шістнадцятковій?
ПІнтаг

1
Зазначена довжина - кількість байтів випадковості (або "ентропія", як це відомо технічно). Однак повернене значення кодується base-64, що означає, що через те, як працює кодування base-64, довжина виводу завжди кратна 4. Іноді це більше символів, ніж потрібно для кодування всіх символів, тому воно використовує = символи, щоб залишити решту.
anaximander

1
RNGCryptoServiceProvider є ідентифікатором, тому я би реалізував його за допомогою шаблону (тобто, використовуючи (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
///////////////////////////////////////////////////////////////////////////////

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 видає цілі числа, менші за вказане число, тому не слід віднімати додаткове одне від довжини.
notbono

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, щоб зробити всі заміни, але це більш читабельний та ремонтований ІМО.


2
GUID не слід зловживати як криптовалюта
PRNG

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. Додана ентропія, якщо ви робите кілька дзвінків одночасно. Це означає, що називається сон () або інша ентропія, що викликає функцію між дзвінками. 2. Збільшити кількість та випадковість вихідних символів. Я створив серію з 500 паролів char із ключем, що виключає купу подібних та інших символів, з якими я не міг працювати, і використав отриманий рядок 2000 символів. Випадковість після навіть 100 м Ентропії була досить хорошою.
Wizengamot

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 .


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

Це може "працювати", але це, безумовно, не безпечно. Паролі потрібно захистити.
CodesInChaos

Я думаю, що випадкові паролі - це тимчасові паролі. Не розумійте, чому вони повинні бути захищеними, і навіть якщо вони це роблять, ви можете додавати цифри та спеціальні символи в діапазоні.
користувач1058637

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для списку масивів.


Як уже сказано в описі редагування. Якщо ви посилаєтесь на свій веб-сайт, не посилаючись на код, ви суто рекламуєте, що робить його спамом, тому видаліть це посилання зі своєї відповіді.
Bowdzone

0

До прийнятої відповіді додано додатковий код. Він покращує відповіді, використовуючи лише випадкові випадки, і дозволяє отримати деякі варіанти пароля. Мені також сподобалися деякі варіанти відповіді 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 для безпечного зберігання паролів у пам'яті.

FYI, вам не потрібно буде включати виконуваний файл 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();
    }

Відповіді на код не рекомендуються, оскільки вони не надають багато інформації майбутнім читачам. Будь ласка, надайте пояснення тому, що ви написали
WhatsThePoint

Створюється один і той же пароль знову і знову. Потрібно мати примірник Randomяк static
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);
}

-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

Вставте таймер: 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.