임의의 비밀번호 생성


229

당사 사이트의 사용자가 비밀번호를 잊어 버려 비밀번호 분실 페이지로 이동하면 새 임시 비밀번호를 제공해야합니다. 나는 이것이 얼마나 무작위인지, 또는 모든 "필요한"강력한 암호 규칙과 일치하는 경우 나중에 변경할 수있는 암호를 제공하기 만하면됩니다.

응용 프로그램은 C #으로 작성된 웹 응용 프로그램입니다. 그래서 나는 의미가 있다고 생각하고 Guid의 일부를 사용하는 쉬운 길을 가고있었습니다. 즉

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

제안? 생각?


12
여기에 몇 가지 좋은 솔루션,하지만 약간의 조언 : 음주 이러한 문자가 포함 된 암호를 생성하지 : Oo0Ili (당신이 왜 참조) :
stian.net

2
KeePass를 암호 생성기로 사용하는 답변을 추가했으며 노출 된 많은 옵션 중 @ stian.net에서 언급 한 것처럼 닮은 문자를 제외하는 옵션도 포함했습니다.
피터

답변:


570

7
프레임 워크에 그러한 방법이 있다는 것을 몰랐습니다! 대박! 현재 코드를 스왑합니다!
FryHard

35
내 자신의 pw gen 코드를 완성하는 데 거의 하루를 보낸 후 그것을 발견했습니다. 내가 어떻게 느꼈는지 이미지))
Rik

16
AFAIK이 방법은 도메인의 비밀번호 정책을 준수하는 비밀번호를 생성하지 않으므로 모든 용도에 적합하지 않습니다.
teebot

19
이 솔루션의 주된 문제점은 문자 집합을 제어 할 수 없으므로 시각적으로 모호한 문자 (0oO1i! |)를 제거 할 수 없으므로 실제로 중요합니다.
David Hammond

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)보다 우수합니다. 8 문자 16 진 문자열은 4-5 자의 영숫자 문자와 동일합니다
Jimmy

57
Random암호화 적으로 안전하지 않습니다. System.Security.Cryptography.RNGCryptoServiceProvider더 나은 선택입니다.
anaximander

3
Random 클래스가 매번 인스턴스화되므로 메소드가 호출 될 때마다 동일한 비밀번호가 생성됩니다. 이 방법에서 Random을 옮기고 인스턴스를 재사용하면 보안을 유지할 수 있습니다.
Jon

6
아닙니다. 두 사람이 같은 시간에 암호를 변경하기로 결정하지 않는 한.
Radu094

10
질문에서 인용 : "모든"필요한 "강력한 암호 규칙과 일치하는 경우"상관 없어요 ...이 답변을 하향 조정 해 주셔서 감사합니다
Radu094

35

내 코드의 주요 목표는 다음과 같습니다.

  1. 줄의 분포는 거의 균일합니다 (작은 한 작은 편차는 신경 쓰지 마십시오)
  2. 각 인수 세트에 대해 수십억 개 이상의 문자열을 출력합니다. PRNG가 20 억 (31 비트의 엔트로피) 만 다른 값을 생성하는 경우 8 문자열 (~ 47 비트의 엔트로피)을 생성하는 것은 의미가 없습니다.
  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를 characterArray.Length로 균등하게 나눌 수없는 경우 임의로 선택한 문자가 균등하게 분배되지 않습니다 (매우 작은 효과 임).
Jeff Walker 코드 레인저

1
@JeffWalkerCodeRanger 그렇기 때문에 편견이 아닌 무시할만한 편견을 말한 것입니다. 1 페타 바이트의 출력에서도 1 % 미만으로 완벽하게 편향되지 않은 스트링 생성기와 구별 할 수 있습니다. 완벽한 편견의 추가 복잡성은 여기에서 무작위로 이론적으로 이득을 얻을 가치가 없습니다.
코드 InChaos

9
.NET Core를 사용하는 경우 "new 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에서 나오는 전체 범위의 값을 나타낼 수 있고 문자를 보내거나 저장하는 위치와 호환되는 문자를 생성하는 문자 집합을 선택하십시오. 예를 들어, 유니 코드를 사용하면 많은 중국어 문자를 제공하는 경향이 있습니다. base-64를 사용하면 광범위하게 호환되는 문자 집합을 보장 할 수 있으며 적절한 문자열 해싱 알고리즘을 사용하는 한 이러한 문자열의 특성으로 인해 보안 수준이 떨어지지 않아야합니다.


linkBuf가있는 곳에 tokenBuffer를 넣는 것을 의미한다고 생각합니다.
PIntag

이 코드를 사용하고 길이 10을 전달하면 반환되는 문자열의 길이는 항상 16 자이며 마지막 2자는 항상 "=="입니다. 잘못 사용하고 있습니까? 길이는 16 진수로 지정되어 있습니까?
PIntag

1
지정된 길이는 임의의 바이트 수 (또는 기술적으로 알려진 "엔트로피")입니다. 그러나 반환 된 값은 base-64로 인코딩됩니다. 즉 base-64 인코딩의 작동 방식으로 인해 출력 길이는 항상 4의 배수입니다. 때로는 모든 문자를 인코딩하는 데 필요한 것보다 많은 문자가 사용되므로 = 나머지 문자를 제거 할 문자
anaximander

1
RNGCryptoServiceProvider는 IDisposable이므로 사용 패턴을 사용하여 구현합니다 (예 : (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

1
출력 크기가 길더라도 2 ^ 31 개의 서로 다른 비밀번호 만 생성하는 것은 낮은 편입니다. 온라인 공격에 대해서는 충분하지만 오프라인 공격에 대해서는 작을 수 있습니다. => 나는 이것을 권장하지 않습니다.
코드 InChaos

"기본 제공"지원은 실제로 멤버쉽이므로 ASP.NET 멤버쉽을 사용하지 않기로 결정한 경우 어떻게됩니까? 종속성이 System.Web.dll이기 때문에 여전히 작동하지만 메서드가 자체 포함되어 있지 않기 때문에 조금 어색합니다. @GEOCHET :이 대안을 게시 해 주셔서 감사합니다.
Chris Gomez

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,}$

이 질문의 범위를 벗어 났지만 정규 표현식은 lookahead / lookbehindlookaround를 기반으로 합니다.

다음 코드는이 요구 사항과 일치하는 임의의 문자 집합을 만듭니다.

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
코드 InChaos

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

3
이 방법을 사용하려는 경우 .ToString ( "N")을 사용할 수 있으며 "-"를 바꿀 필요가 없습니다. "l"은 16 진수가 아니기 때문에 바꿀 필요가 없습니다.
JackAce

왜 당신이 이것을했는지 완전히보십시오. 사용자별로 고유하지 않아도되는 짧은 수명 (하루 미만)의 비밀번호가 필요했습니다. 1과 0을 얀킹하는 것은 혼란을 없애는 좋은 방법입니다. 또한 방금 대문자로 바꾸고 길이를 6으로 줄였습니다. 'N'제안과 마찬가지로. 감사!
Bill Noel

6

RNGCryptoServiceProvider를 사용하는 이 클래스 를 만들었 으며 융통성이 있습니다. 예:

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

그 클래스의 라이센스는 무엇입니까? 사용할 수 있습니까?
codeulike 19

원하는대로 사용하십시오!
Alex Siepman 19

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
코드 InChaos

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. 소스 문자의 수와 임의성을 증가시킵니다. 처리하지 않으려는 유사하고 다른 이스케이프 문자를 제외하고 키 패스로 일련의 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: 무작위의 주요 원천은 여전히 ​​crypto RNG입니다. 시퀀스에서 나오는 시퀀스를 결정적으로 미리 결정할 수 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

알파벳, 숫자 및 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();
}

"작동"할 수 있지만 확실하지 않습니다. 비밀번호는 안전해야합니다.
코드 InChaos

임의의 암호는 임시 암호라고 생각합니다. 왜 안전해야하는지 알 수 없으며, 그렇게해도 범위에 숫자와 특수 문자를 추가 할 수 있습니다.
user1058637

1
예측 가능한 PRNG를 사용하여 숫자와 특수 문자를 추가해도 보안이 향상되지는 않습니다. 비밀번호가 생성 된시기를 아는 경우 소수의 후보로만 좁힐 수 있습니다.
코드 InChaos

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 을 사용 하여 구현하는 방법을 고려할 수 있습니다.

참고로, 공개 소스이므로 KeyPass 실행 파일을 포함하지 않아도됩니다 (소스 코드는 여기 에서 다운로드 가능 )
Alex Klaus

0

validChars는 모든 구성이 될 수 있지만 제어 문자를 제거하는 ASCII 코드 범위를 기반으로 선택하기로 결정했습니다. 이 예에서는 12 자 문자열입니다.

string validChars = String.Join("", Enumerable.Range(33, (126 - 33)).Where(i => !(new int[] { 34, 38, 39, 44, 60, 62, 96 }).Contains(i)).Select(i => { return (char)i; }));
string.Join("", Enumerable.Range(1, 12).Select(i => { return validChars[(new Random(Guid.NewGuid().GetHashCode())).Next(0, validChars.Length - 1)]; }))

0
 Generate random password of specified length with 
  - Special characters   
  - Number
  - Lowecase
  - Uppercase

  public static string CreatePassword(int length = 12)
    {
        const string lower = "abcdefghijklmnopqrstuvwxyz";
        const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const string number = "1234567890";
        const string special = "!@#$%^&*";

        var middle = length / 2;
        StringBuilder res = new StringBuilder();
        Random rnd = new Random();
        while (0 < length--)
        {
            if (middle == length)
            {
                res.Append(number[rnd.Next(number.Length)]);
            }
            else if (middle - 1 == length)
            {
                res.Append(special[rnd.Next(special.Length)]);
            }
            else
            {
                if (length % 2 == 0)
                {
                    res.Append(lower[rnd.Next(lower.Length)]);
                }
                else
                {
                    res.Append(upper[rnd.Next(upper.Length)]);
                }
            }
        }
        return res.ToString();
    }

미래 독자들에게 많은 정보를 제공하지
않기

동일한 비밀번호를 반복해서 만듭니다. Random정적 인스턴스가 필요함
trailmax

이 답변은 여러 번 연속해서 호출되면 동일한 비밀번호를 생성합니다! 코드를 사용하여 한 번에 여러 레코드에 암호를 할당하는 기능을 사용하려면 호출간에 Entropy를 추가해야합니다. 여전히 유용하지만 ....
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

설명이없는 코드 응답 만 삭제 될 수 있습니다.
Rook

-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보안을 위해 사용하지 마십시오 .
코드 InChaos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.