ランダムパスワードの生成


229

私たちのサイトのユーザーが自分のパスワードを失い、Lost Passwordページに向かうとき、私たちは彼に新しい一時的なパスワードを与える必要があります。これがどれほどランダムかは気にしませんが、「必要な」強力なパスワードルールにすべて一致する場合は、後で変更できるパスワードを与えるだけです。

アプリケーションは、C#で記述されたWebアプリケーションです。だから私は卑劣で、Guidの一部を使用する簡単なルートに行くことを考えていました。すなわち

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

提案?考え?


12
ここにいくつかの良い解決策がありますが、少しアドバイス:これらの文字のいずれかを含むパスワードを生成しないでください:Oo0Ili(理由がわかります):)
stian.net

2
パスワードジェネレーターとしてKeePassを使用する回答を追加しました。公開されている多くのオプションの中で、@ stian.netで言及されているように、似ている文字を除外するオプションも含めました。
Peter

回答:


570

7
フレームワークにそのようなメソッドがあることを知りませんでした!驚くばかり!これのために私の現在のコードを交換します!
FryHard 2008

35
私は自分のpw genコードを完成させるためにほぼ1日を費やした後にそれを見つけました。私が感じたイメージ;)
Rik

16
私の知る限り、この方法ではドメインのパスワードポリシーに準拠したパスワードが生成されないため、すべての用途に適しているわけではありません。
teebot 2010

19
このソリューションの主な問題は、文字セットを制御できないため、実際には非常に重要である視覚的にあいまいな文字(0oOl1i!|)を排除できないことです。
デビッドハモンド

20
何かASP.NET Core
shashwat 2016年

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進法)よりも強度が優れています。8文字の16進文字列は、4〜5文字の英数字の文字列に相当します
Jimmy

57
Random暗号的に安全ではありません。System.Security.Cryptography.RNGCryptoServiceProviderより良い選択です。
anaximander

3
これにより、Randomクラスが毎回インスタンス化されるため、メソッドが呼び出されるたびに同じパスワードが生成されます。Randomをこのメソッドから移動し、インスタンスを再利用することで、これを安全にすることができます。
Jon

6
いいえ、そうではありません。2人が同じ時刻にパスワードを変更することを決定した場合を除きます。
Radu094 14年

10
質問からの引用:「すべての「必要な」強力なパスワードルールに一致する場合」は気にしないでください...ただし、この回答に
反対票を投じて

35

私のコードの主な目標は次のとおりです。

  1. 文字列の分布はほぼ均一です(小さい限り、小さな偏差は気にしないでください)。
  2. 引数セットごとに数十億以上の文字列を出力します。PRNGが20億(31ビットのエントロピー)だけの異なる値を生成する場合、8文字の文字列(47ビットのエントロピー)を生成しても意味がありません。
  3. パスワードやその他のセキュリティトークンに使用することを期待しているので、安全です。

最初のプロパティは、アルファベットサイズを法とする64ビット値を取ることによって実現されます。小さなアルファベット(質問の62文字など)の場合、これは無視できるバイアスにつながります。2番目と3番目のプロパティは、の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);
}

(これは、C#でランダムな8文字の英数字の文字列を生成するにはどうすればよいですか?)への私の回答のコピーです。


1
UInt64.MaxValueがcha​​racterArray.Lengthで割り切れない場合、ランダムに選択された文字は均等に分散されません(ただし、これは非常に小さな効果です)。
ジェフウォーカーコードレンジャー

1
@JeffWalkerCodeRangerそのため、私はバイアスを無視するのではなく、無視できるバイアスと述べました。ペタバイトの出力を使用しても、これを完全に公平な文字列ジェネレータと区別するために1%未満です。完全なバイアスを解除することによる複雑さの増加は、ここでランダム性を理論的に向上させる価値がないことは明らかです。
CodesInChaos 2014

9
.NET Coreを使用している場合は、「new RNGCryptoServiceProvider()。GetBytes(bytes);」に置き換えます。「System.Security.Cryptography.RandomNumberGenerator.Create()。GetBytes(bytes);」
NPNelson 2017年

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を使用すると、互換性のある文字セットが保証されます。また、適切なハッシュアルゴリズムを使用している限り、そのような文字列の特性によって、文字列の安全性が低下することはありません。


linkBufがある場所にtokenBufferを置くつもりだと思います。
PIntag 2015

このコードを使用して長さ10を渡すと、返される文字列は常に16文字で、最後の2文字は常に「==」になります。間違って使用していますか?長さは16進数で指定されていますか?
PIntag 2015年

1
指定された長さは、ランダム性(または技術的に知られている「エントロピー」)のバイト数です。ただし、戻り値はbase-64エンコードされます。つまり、base-64エンコードが機能するため、出力の長さは常に4の倍数になります。場合によっては、すべての文字をエンコードするのに必要な文字数よりも多くなるため、 =残りを埋める文字。
anaximander

1
RNGCryptoServiceProviderはIDisposableであるため、usingパターンを使用して実装します(つまり、(var cryptRNG = new RNGCryptoServiceProvider()){...})
kloarubeek

@kloarubeek有効なポイントであり、良い提案です。これをコードサンプルに追加しました。
anaximander

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 2008

1
出力サイズが長い場合でも、2 ^ 31の異なるパスワードのみを生成することは、少々有利です。オンライン攻撃に対しては十分かもしれませんが、オフライン攻撃に対しては確かに小規模です。=>これはお勧めしません。
CodesInChaos 2013年

「組み込み」サポートは実際にはメンバーシップであるため、これは良い答えです。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 2013

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を使用してすべての置換を行うことはできますが、これはより読みやすく保守しやすいIMOです。


2
GUIDを暗号PRNGとして悪用しないでください
CodesInChaos 2013

3
このメソッドを使用する場合は、.ToString( "N")を使用できます。 "-"を置き換える必要はありません。また、「l」は16進数ではないので、置き換える必要はありません。
JackAce

あなたがこれをした理由を完全に見てください。ユーザーごとに一意である必要はなく、有効期間が短い(1日未満)パスワードが必要でした。1と0をヤンクアウトすることは、混乱をなくすための優れた方法です。私も大文字に変更し、長さを6に切りました。「N」の提案も同様です。ありがとう!
ビル・ノエル

6

RNGCryptoServiceProviderを使用するこのクラスを作成しました。これは柔軟です。例:

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

それは素晴らしいです、そのクラスのライセンスはどうですか?使えますか?
-codeulike

好きなように使ってください!
Alex Siepman

3

このメソッドは、メンバーシッププロバイダーで利用可能なものと同様に作成しました。これは、一部のアプリケーションでWeb参照を追加したくない場合に役立ちます。

それは素晴らしい働きをします。

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 2013

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

回答を説明してください
Linus

1
この機能は、いくつかの変更で非常にうまく機能します。1.一度に複数の呼び出しを行う場合は、エントロピーを追加しました。これは、Sleep()、または呼び出し間で関数を引き起こすその他のエントロピーが呼び出されたことを意味します。2.ソースキャラクターの数とランダム性を増やします。処理したくない類似の文字や他の回避可能な文字の束を除いて、keypassを使用して一連の500文字のパスワードを作成し、結果の2000文字の文字列を使用しました。たった100msのエントロピーの後のランダム性はかなり良かったです。
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:ランダム性の主な原因は依然として暗号RNGです。出てくるシーケンスを決定論的に前もって調整できたとしてもRandom(それが生成されただけだと言って1も)、次に選択される文字がわからないでしょう(ただし、それによって可能性の範囲制限されます)。

簡単な拡張の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

私はこのコードを使用して、アルファベット、数字、および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;
    }

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 14

ランダムなパスワードは一時的なパスワードだと思います。それらが安全である必要がある理由はわかりません。たとえ安全であっても、範囲内に数字と特殊文字を追加できます。
user1058637 2014年

1
数値や特殊文字を追加しても、予測可能なPRNGを使用してそれらを生成した場合、セキュリティは向上しません。パスワードがいつ生成されたかがわかっている場合は、それをいくつかの候補だけに絞り込むことができます。
CodesInChaos 2014年

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、2015年

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を実装することを検討したい場合があります。

参考までに、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静的インスタンスを必要とする
Trailmax

この回答は、連続して複数回呼び出された場合に同じパスワードを生成することに注意してください!!! 関数を使用してコードを使用してパスワードを一度に複数のレコードに割り当てる場合は、呼び出しの間にエントロピーを追加する必要があります。まだ便利ですが...
Wizengamot


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;



}

コードの機能とその理由を説明してください。レビューから
Wai Ha Lee

説明のない回答のみのコードは削除される可能性があります。
2016年

-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 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.