Menghasilkan Kata Sandi Acak

229

Ketika seorang pengguna di situs kami kehilangan kata sandinya dan menuju ke halaman Kata Sandi Hilang kami perlu memberinya kata sandi sementara yang baru. Saya tidak terlalu peduli seberapa acak ini, atau jika cocok dengan semua aturan kata sandi yang kuat "yang dibutuhkan", yang ingin saya lakukan adalah memberi mereka kata sandi yang dapat mereka ubah nanti.

Aplikasi ini adalah aplikasi Web yang ditulis dalam bahasa C #. jadi saya berpikir untuk menjadi jahat dan pergi untuk rute yang mudah menggunakan bagian dari Guid. yaitu

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

Saran? pikiran?

FryHard
sumber
12
Beberapa solusi bagus di sini, tetapi sedikit saran: Jangan menghasilkan kata sandi yang mengandung salah satu dari karakter ini: Oo0Ili (Anda mengerti mengapa) :)
stian.net
2
Saya telah menambahkan jawaban yang menggunakan KeePass sebagai penghasil kata sandi, dan dari sekian banyak opsi yang ada, saya juga menyertakan opsi untuk mengecualikan karakter yang mirip, seperti disebutkan oleh @ stian.net.
Peter

Jawaban:

570

Selalu ada System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters) .

Rik
sumber
7
Tidak tahu bahwa Kerangka ini memiliki metode seperti itu! Luar biasa! Akan menukar kode saya saat ini untuk ini!
FryHard
35
Saya menemukannya setelah menghabiskan hampir sehari menyempurnakan kode gen pw saya sendiri. Gambar bagaimana saya rasakan;)
Rik
16
AFAIK metode ini tidak menghasilkan kata sandi yang mematuhi kebijakan kata sandi di domain sehingga tidak cocok untuk setiap penggunaan.
teebot
19
Masalah utama dengan solusi ini adalah bahwa Anda tidak dapat mengontrol set karakter, sehingga Anda tidak dapat menghilangkan karakter ambigu visual (0oOl1i! |) Yang bisa sangat penting dalam praktik.
David Hammond
20
Ada sesuatu untuk 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();
}

Ini memiliki manfaat yang baik karena dapat memilih dari daftar karakter yang tersedia untuk kata sandi yang dihasilkan (mis. Digit saja, hanya huruf besar atau hanya huruf kecil, dll.)

Radu094
sumber
2
metode ini (base 62) lebih unggul daripada GUID (base 16) pada kekuatan: string hex 8-char setara dengan 4-5 char alphanumeric one
Jimmy
57
Randomtidak aman secara kriptografis; System.Security.Cryptography.RNGCryptoServiceProvideradalah pilihan yang lebih baik.
anaximander
3
Ini akan menghasilkan kata sandi yang sama setiap kali metode dipanggil, karena kelas Acak dipakai setiap kali. Ini dapat dibuat aman dengan memindahkan Random keluar dari metode ini dan menggunakan kembali instance.
Jon
6
Tidak, itu tidak akan terjadi. Kecuali dua orang memutuskan untuk mengubah kata sandi pada jam yang sama.
Radu094
10
kutipan dari pertanyaan: tidak peduli "jika cocok dengan semua" yang diperlukan "aturan kata sandi yang kuat" ... terima kasih telah
menurunkan
35

Tujuan utama kode saya adalah:

  1. Distribusi string hampir seragam (tidak peduli dengan penyimpangan kecil, asalkan kecil)
  2. Ini menghasilkan lebih dari beberapa miliar string untuk setiap set argumen. Menghasilkan string 8 karakter (~ 47 bit entropi) tidak ada artinya jika PRNG Anda hanya menghasilkan 2 miliar (31 bit entropi) nilai yang berbeda.
  3. Ini aman, karena saya berharap orang menggunakan ini untuk kata sandi atau token keamanan lainnya.

Properti pertama dicapai dengan mengambil modulo nilai alfabet 64 bit. Untuk huruf kecil (seperti 62 karakter dari pertanyaan) ini menyebabkan bias diabaikan. Properti kedua dan ketiga dicapai dengan menggunakan RNGCryptoServiceProvideralih-alih 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);
}

(Ini adalah salinan jawaban saya untuk Bagaimana saya bisa menghasilkan 8 karakter acak, string alfanumerik dalam C #? )

CodesInChaos
sumber
1
Jika UInt64.MaxValue tidak terbagi rata oleh characterArray.Length maka karakter yang dipilih secara acak tidak akan terdistribusi secara merata (meskipun ini akan menjadi efek yang sangat kecil).
Jeff Walker Code Ranger
1
@JeffWalkerCodeRanger Itu sebabnya saya katakan bias diabaikan, tidak ada bias. Bahkan dengan petabyte output Anda memiliki kurang dari 1% untuk membedakan ini dari generator string yang tidak bias sempurna. Kompleksitas tambahan unbiasing sempurna jelas tidak sebanding dengan perolehan yang agak teoretis dalam keacakan di sini.
CodesInChaos
9
Bagi mereka yang menggunakan .NET Core, gantikan "RNGCryptoServiceProvider () baru. GetBytes (bytes);" dengan "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);
    }
}

(Anda juga dapat memiliki kelas tempat metode ini menerapkan IDisposable, tahan referensi ke RNGCryptoServiceProvider , dan membuangnya dengan benar, untuk menghindari berulang kali instantiate itu.)

Telah dicatat bahwa saat ini mengembalikan string base-64, panjang output selalu kelipatan 4, dengan ruang tambahan menggunakan =sebagai karakter padding. The lengthparameter menentukan panjang buffer byte, bukan string output (dan oleh karena itu mungkin bukan nama yang terbaik untuk parameter itu, sekarang aku berpikir tentang hal). Ini mengontrol berapa banyak byte entropi kata sandi yang akan dimiliki. Namun, karena base-64 menggunakan blok 4-karakter untuk mengkodekan setiap 3 byte input, jika Anda meminta panjang yang bukan kelipatan 3, akan ada beberapa "ruang" tambahan, dan itu akan digunakan =untuk mengisi tambahan.

Jika Anda tidak suka menggunakan string base-64 karena alasan apa pun, Anda dapat mengganti Convert.ToBase64String()panggilan dengan konversi ke string biasa, atau dengan Encodingmetode apa pun ; misalnya. Encoding.UTF8.GetString(tokenBuffer)- pastikan Anda memilih rangkaian karakter yang dapat mewakili rentang nilai penuh yang keluar dari RNG, dan yang menghasilkan karakter yang kompatibel dengan di mana pun Anda mengirim atau menyimpan ini. Menggunakan Unicode, misalnya, cenderung memberi banyak karakter Cina. Menggunakan base-64 menjamin serangkaian karakter yang kompatibel secara luas, dan karakteristik string seperti itu seharusnya tidak membuatnya kurang aman selama Anda menggunakan algoritma hashing yang layak.

anaximander
sumber
Saya pikir Anda bermaksud menempatkan tokenBuffer di mana Anda memiliki linkBuf.
PIntag
Ketika saya menggunakan kode ini dan memberikan panjang 10, string yang dikembalikan selalu 16 karakter dan 2 karakter terakhir selalu "==". Apakah saya salah menggunakannya? Apakah panjangnya ditentukan dalam hex?
PIntag
1
Panjang yang ditentukan adalah jumlah byte dari keacakan (atau "entropi", seperti yang dikenal secara teknis). Namun, nilai yang dikembalikan adalah pengkodean basis-64, yang berarti bahwa karena cara kerja pengkodean basis-64, panjang keluaran selalu merupakan kelipatan dari 4. Kadang-kadang, itu lebih banyak karakter daripada yang dibutuhkan untuk menyandikan semua karakter, sehingga menggunakan = karakter untuk mengisi sisanya.
anaximander
1
RNGCryptoServiceProvider adalah IDisposable, jadi saya akan menerapkannya dengan pola using (yaitu menggunakan (var cryptRNG = new RNGCryptoServiceProvider ()) {...})
kloarubeek
@ kloarubeek Poin yang valid, dan saran yang bagus. Saya telah menambahkan itu ke contoh kode saya.
anaximander
20

Ini jauh lebih besar, tapi saya pikir itu terlihat sedikit lebih komprehensif: http://www.obviex.com/Samples/Password.aspx

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/// <summary>
/// Illustrates the use of the RandomPassword class.
/// </summary>
public class RandomPasswordTest
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        // Print 100 randomly generated passwords (8-to-10 char long).
        for (int i=0; i<100; i++)
            Console.WriteLine(RandomPassword.Generate(8, 10));
    }
}
//
// END OF FILE
///////////////////////////////////////////////////////////////////////////////
GEOCHET
sumber
2
Ternyata ada dukungan untuk ini oleh kerangka kerja. Jadi saya menerima jawaban itu!
FryHard
1
Menghasilkan hanya 2 ^ 31 kata sandi yang berbeda, bahkan dengan ukuran keluaran yang panjang, agak rendah. Mungkin cukup terhadap serangan online, tetapi yang pasti kecil untuk serangan offline. => Saya tidak akan merekomendasikan ini.
CodesInChaos
Ini masih merupakan jawaban yang bagus karena dukungan "bawaan" benar-benar Keanggotaan, dan bagaimana jika Anda memutuskan untuk tidak menggunakan Keanggotaan ASP.NET? Ini masih berfungsi, karena ketergantungannya adalah System.Web.dll, tapi agak canggung karena metode ini tidak mandiri. @GEOCHET: Terima kasih telah memposting alternatif ini.
Chris Gomez
8

Saya tahu ini adalah utas lama, tetapi saya memiliki apa yang mungkin merupakan solusi yang cukup sederhana untuk digunakan seseorang. Mudah diimplementasikan, mudah dimengerti, dan mudah divalidasi.

Pertimbangkan persyaratan berikut:

Saya perlu kata sandi acak yang dihasilkan yang memiliki setidaknya 2 huruf kecil, 2 huruf besar dan 2 angka. Panjang kata sandi juga harus minimal 8 karakter.

Ekspresi reguler berikut dapat memvalidasi kasus ini:

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

Itu di luar ruang lingkup pertanyaan ini - tetapi regex didasarkan pada lookahead / lookbehind dan lookaround .

Kode berikut akan membuat serangkaian karakter acak yang cocok dengan persyaratan ini:

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

}

Untuk memenuhi persyaratan di atas, cukup hubungi yang berikut ini:

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

Kode dimulai dengan karakter yang tidak valid ("!" ) - sehingga string memiliki panjang untuk memasukkan karakter baru.

Itu kemudian loop dari 1 ke # karakter huruf kecil yang diperlukan, dan pada setiap iterasi, ambil item acak dari daftar huruf kecil, dan menyuntikkannya di lokasi acak dalam string.

Itu kemudian mengulangi loop untuk huruf besar dan angka.

Ini memberi Anda kembali string panjang = lowercase + uppercase + numericske mana karakter huruf kecil, huruf besar dan numerik dari jumlah yang Anda inginkan telah ditempatkan dalam urutan acak.

Troy Alford
sumber
3
Jangan gunakan System.Randomuntuk hal-hal penting keamanan seperti kata sandi. GunakanRNGCryptoServiceProvider
CodesInChaos
lowers[random.Next(lowers.Length - 1)].ToString() Kode ini tidak akan pernah menghasilkan 'z'. acak. Berikutnya menghasilkan bilangan bulat kurang dari jumlah yang disediakan, jadi Anda tidak harus mengurangi yang ekstra dari panjangnya.
notbono
6

Untuk jenis kata sandi ini, saya cenderung menggunakan sistem yang cenderung menghasilkan kata sandi "bekas" yang lebih mudah. Pendek, sering terdiri dari fragmen yang dapat diucapkan dan beberapa angka, dan tanpa ambiguitas intercharacter (apakah itu 0 atau O? A 1 atau I?). Sesuatu seperti

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;

(Diketik langsung di browser, jadi gunakan hanya sebagai pedoman. Juga, tambahkan lebih banyak kata).

Adam Wright
sumber
6

Saya tidak suka kata sandi yang dibuat oleh Membership.GeneratePassword (), karena terlalu jelek dan memiliki terlalu banyak karakter khusus.

Kode ini menghasilkan kata sandi 10 digit tidak terlalu jelek.

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

Tentu, saya bisa menggunakan Regex untuk melakukan semua penggantian tetapi IMO ini lebih mudah dibaca dan dikelola.

Matt Frear
sumber
2
GUID tidak boleh disalahgunakan sebagai crypto PRNG
CodesInChaos
3
Jika Anda akan menggunakan metode ini, Anda dapat menggunakan .ToString ("N") dan Anda tidak perlu mengganti "-". Juga tidak perlu mengganti "l", karena itu bukan digit hex.
JackAce
Benar-benar mengerti mengapa Anda melakukan ini. Saya hanya perlu kata sandi yang berumur pendek (kurang dari sehari) yang tidak harus terlalu unik untuk setiap pengguna. Menarik satu dan nol adalah cara yang bagus untuk menghilangkan kebingungan. Saya juga hanya menggeser milik saya ke huruf besar dan kemudian memotong panjangnya menjadi 6. Seperti saran 'N' juga. Terima kasih!
Bill Noel
6

Saya membuat kelas ini yang menggunakan RNGCryptoServiceProvider dan fleksibel. Contoh:

var generator = new PasswordGenerator(minimumLengthPassword: 8,
                                      maximumLengthPassword: 15,
                                      minimumUpperCaseChars: 2,
                                      minimumNumericChars: 3,
                                      minimumSpecialChars: 2);
string password = generator.Generate();
Alex Siepman
sumber
Bagus sekali, apa lisensi untuk kelas itu? Bisakah saya menggunakannya?
codeulike
Gunakan seperti yang Anda inginkan!
Alex Siepman
3

Saya membuat metode ini mirip dengan yang tersedia di penyedia keanggotaan. Ini berguna jika Anda tidak ingin menambahkan referensi web di beberapa aplikasi.

Ini bekerja dengan baik.

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;
    }
Hugo
sumber
6
Jangan gunakan System.Randomuntuk hal-hal penting keamanan seperti kata sandi. GunakanRNGCryptoServiceProvider
CodesInChaos
3

Saya selalu sangat senang dengan generator kata sandi bawaan untuk KeePass. Karena KeePass adalah program .Net, dan open source, saya memutuskan untuk menggali sedikit kode. Saya akhirnya hanya merujuk KeePass.exe, salinan yang disediakan dalam instalasi aplikasi standar, sebagai referensi dalam proyek saya dan menulis kode di bawah ini. Anda dapat melihat betapa fleksibelnya ini berkat KeePass. Anda dapat menentukan panjang, karakter mana yang akan dimasukkan / tidak disertakan, dll ...

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();
    }
Peter
sumber
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;
    }
kata Ahmad
sumber
Tolong jelaskan jawaban Anda
Linus
1
Fungsi ini berfungsi sangat baik dengan beberapa perubahan. 1. Menambahkan entropi jika Anda melakukan beberapa panggilan sekaligus. Ini berarti disebut Sleep () atau entropi lain yang menyebabkan fungsi antar panggilan. 2. Tingkatkan jumlah dan keacakan karakter sumber. Saya membuat serangkaian 500 kata sandi char dengan keypass tidak termasuk sekelompok karakter yang mirip dan lolos lainnya saya tidak ingin berurusan dengan dan menggunakan string karakter 2000 yang dihasilkan. Keacakan setelah hanya 100ms Entropy cukup bagus.
Wizengamot
2

Saya akan menambahkan jawaban keliru lainnya ke pot.

Saya memiliki kasus penggunaan di mana saya memerlukan kata sandi acak untuk komunikasi mesin-mesin, jadi saya tidak memiliki persyaratan untuk keterbacaan manusia. Saya juga tidak memiliki akses ke Membership.GeneratePassworddalam proyek saya, dan tidak ingin menambahkan ketergantungan.

Saya cukup yakin Membership.GeneratePasswordmelakukan sesuatu yang mirip dengan ini, tetapi di sini Anda dapat mengatur kumpulan karakter untuk menggambar.

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

Dan beberapa contoh output:

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

Untuk mencegah keluhan tentang penggunaan Random: Sumber utama keacakan adalah RNG crypto. Bahkan jika Anda dapat menentukan terlebih dahulu urutan keluar dari Random(katakan itu hanya diproduksi 1), Anda masih tidak akan tahu karakter berikutnya yang akan dipilih (meskipun itu akan membatasi berbagai kemungkinan).

Satu ekstensi sederhana adalah dengan menambahkan bobot ke set karakter yang berbeda, yang bisa sesederhana menaikkan nilai maksimal dan menambahkan kasing jatuh untuk menambah bobot.

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

Untuk pembuat kata sandi acak yang lebih humanistik, saya pernah menerapkan sistem yang cepat menggunakan daftar kata dadu EFF .

kitsu.eb
sumber
1

Saya suka melihat cara membuat kata sandi, seperti halnya membuat kunci perangkat lunak. Anda harus memilih dari serangkaian karakter yang mengikuti praktik yang baik. Ambil apa yang dijawab @ Radu094 dan modifikasi untuk mengikuti praktik yang baik. Jangan letakkan setiap huruf di dalam array karakter. Beberapa surat lebih sulit diucapkan atau dipahami melalui telepon.

Anda juga harus mempertimbangkan untuk menggunakan checksum pada kata sandi yang dibuat untuk memastikan bahwa itu dihasilkan oleh Anda. Cara yang baik untuk mencapai ini adalah dengan menggunakan algoritma LUHN .

Dale Ragan
sumber
1

Inilah yang saya kumpulkan dengan cepat.

    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;
    }
Skyler Campbell
sumber
1

Saya menggunakan kode ini untuk menghasilkan kata sandi dengan komposisi keseimbangan karakter alfabet, numerik dan 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;
    }
Roohi Ali
sumber
0

Ini singkat dan itu sangat bagus untuk saya.

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();
}
pengguna1058637
sumber
Ini mungkin "bekerja", tetapi tentu saja tidak aman. Kata sandi harus aman.
CodesInChaos
Saya pikir kata sandi acak adalah kata sandi sementara. Jangan melihat mengapa mereka harus aman, dan bahkan jika mereka melakukannya, Anda dapat menambahkan angka dan karakter khusus dalam jangkauan.
user1058637
1
Menambahkan angka dan karakter khusus tidak meningkatkan keamanan jika Anda membuatnya menggunakan PRNG yang dapat diprediksi. Jika Anda tahu kapan kata sandi dibuat, Anda dapat mempersempitnya menjadi hanya beberapa kandidat.
CodesInChaos
0

Di situs web saya, saya menggunakan metode ini:

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

Edit string _SymbolsAlluntuk daftar array Anda.

GRUNGER
sumber
Seperti yang sudah dinyatakan dalam deskripsi edit. Jika Anda menautkan ke situs web tanpa menjadi referensi kode, Anda murni beriklan yang menjadikannya spam, jadi harap hapus tautan itu dari jawaban Anda.
Bowdzone
0

Menambahkan beberapa kode tambahan ke jawaban yang diterima. Ini meningkatkan jawaban hanya menggunakan Acak dan memungkinkan untuk beberapa opsi kata sandi. Saya juga menyukai beberapa opsi dari jawaban KeePass tetapi tidak ingin menyertakan yang dapat dieksekusi dalam solusi saya.

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

Ini adalah tautan pertama ketika saya mencari untuk menghasilkan kata sandi acak dan berikut ini di luar ruang lingkup untuk pertanyaan saat ini tetapi mungkin penting untuk dipertimbangkan.

  • Berdasarkan asumsi yang System.Web.Security.Membership.GeneratePasswordsecara kriptografi aman dengan minimum 20% dari karakter menjadi Non-Alfanumerik.
  • Tidak yakin apakah menghapus karakter dan menambahkan string dianggap praktik yang baik dalam kasus ini dan memberikan cukup entropi.
  • Mungkin ingin mempertimbangkan penerapan dalam beberapa cara dengan SecureString untuk penyimpanan kata sandi yang aman dalam memori.
Mat
sumber
FYI, Anda tidak perlu menyertakan file yang dapat dieksekusi KeyPass, karena ini adalah open source (kode sumber tersedia untuk diunduh di sini )
Alex Klaus
0

validChars dapat berupa konstruksi apa pun, tetapi saya memutuskan untuk memilih berdasarkan rentang kode ascii menghapus chars kontrol. Dalam contoh ini, ini adalah string 12 karakter.

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)]; }))
Sean
sumber
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();
    }
akshay tilekar
sumber
Kode hanya jawaban yang tidak dianjurkan karena mereka tidak memberikan banyak informasi untuk pembaca di masa depan, silakan berikan beberapa penjelasan untuk apa yang telah Anda tulis
WhatsThePoint
Membuat kata sandi yang sama berulang kali. Perlu memiliki contoh Randomsebagai statis
trailmax
Harap dicatat bahwa jawaban ini akan menghasilkan kata sandi yang sama jika dipanggil beberapa kali berturut-turut !!! Harus ada Entropi di antara panggilan jika Anda ingin menggunakan fungsi untuk menetapkan kata sandi menggunakan kode ke beberapa catatan sekaligus. Masih Berguna ...
Wizengamot
0

Paket ini memungkinkan Anda untuk membuat kata sandi acak sambil dengan lancar menunjukkan karakter yang harus dikandungnya (jika perlu):

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

Contoh:

var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();
Johan Maes
sumber
0

Jika Anda ingin menggunakan pembuatan nomor acak kriptografi aman yang digunakan oleh System.Web.Security.Membership.GeneratePassword tetapi juga ingin membatasi set karakter ke karakter alfanumerik, Anda dapat memfilter hasilnya dengan regex:

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



}
Ercan ILIK
sumber
Bisakah Anda menjelaskan apa yang kode Anda lakukan, dan mengapa? Dari Ulasan
Wai Ha Lee
Kode hanya jawaban tanpa penjelasan yang cenderung dihapus.
Benteng
-4

Masukkan Timer: timer1, 2 tombol: button1, button2, 1 textBox: textBox1, dan comboBox: comboBox1. Pastikan Anda menyatakan:

int count = 0;

Kode sumber:

 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;
        }
    }
Joe
sumber
1
Jangan gunakan System.Randomuntuk keamanan.
CodesInChaos