关于.net:在C#中生成一个强密码?

Generating a strong password in C#?

我想知道如何用C语言生成一个安全可靠的密码。

我搜索了一下,在维基百科上看到了这个公式,其中L是密码的长度,N是可能的符号数:

alt text

另外,我也发现了这个问题,但是由于某种原因,方法Membership.GeneratePassword只返回一个1位的随机数,这绝对没有密码。其余的溶液都很慢(>0.5秒)。

我需要帮助实现这个公式(我不知道从哪里开始)。你也可以提出另一个解决方案,或者解释为什么GeneratePassword不起作用。


我刚刚在LinqPad中尝试了以下方法:

1
System.Web.Security.Membership.GeneratePassword(25, 10)

这是我得到的密码:

1
[XTJ_67g.i/ag1rL)6_Yv>*+%

或者,如果这不够安全,请尝试以下操作:

1
System.Web.Security.Membership.GeneratePassword(128, 100)

这让我在运行三次时:

1
2
3
4
5
|c^.:?m)#q+(]V;}[Z(})/?-;$]+@!|^/8*_9.$&.&!(?=^!Wx?[@%+&-@b;)>N;&+*w[>$2+_$%l;+h+#zhs^{e?&=*(}X_%|:}]]}*X[+)Er%J/-=;Q0{:+=%c7:^$

/:_)hxF+*){2|;(>:*N^+!_&|}B.$})?[V=[+v({-:-@9-Z$j?.[-}(@MHx+}(}Mz_S(7#4}{..>@G|!+++{+C=|_}=+r^@&$0;L*|kz-;$++/N3$=}?;%&]]*/^#^!+

:*{]-x^$g{|?*))_=B@^.#%L;g|+)#[nq}?y(_(m;]S^I$*q=l-[_/?}&-!k^(+[_{Z|&:^%!_)!=p%=)=wYd-#.UP$%s1{*l%+[%?!c+7=@=.;{+M)!^}&d/]{];(&}

这只花了不到一秒钟的时间,顺便说一句,框架是你的朋友。

请参阅http://msdn.microsoft.com/en-us/library/system.web.security.membership.generatepassword.aspx


要解决关于该公式的问题:

该公式表示,从n个符号的字母表中提取的长度为l的密码相当于从两个符号的字母表中提取的长度为h的密码。如果你有64个符号(比如abc…xyzabc…xyz01…89!)密码有10个字符长,这就相当于密码的安全性,10 log2 64=60个字符长,从字母"ab"中提取。

"对数"是求幂的逆运算。二到六次方给你六十四次,因此六十四次方的"对数二"给你六次方。


不确定我在哪里找到这个,但这里有一个类来生成高熵,真正的随机字符串,可以用作密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
using System.Security.Cryptography;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class PasswordGenerator
{
    public int MinimumLengthPassword { get; private set; }
    public int MaximumLengthPassword { get; private set; }
    public int MinimumLowerCaseChars { get; private set; }
    public int MinimumUpperCaseChars { get; private set; }
    public int MinimumNumericChars { get; private set; }
    public int MinimumSpecialChars { get; private set; }

    public static string AllLowerCaseChars { get; private set; }
    public static string AllUpperCaseChars { get; private set; }
    public static string AllNumericChars { get; private set; }
    public static string AllSpecialChars { get; private set; }
    private readonly string _allAvailableChars;

    private readonly RandomSecureVersion _randomSecure = new RandomSecureVersion();
    private int _minimumNumberOfChars;

    static PasswordGenerator()
    {
        // Define characters that are valid and reject ambiguous characters such as ilo, IO and 1 or 0
        AllLowerCaseChars = GetCharRange('a', 'z', exclusiveChars:"ilo");
        AllUpperCaseChars = GetCharRange('A', 'Z', exclusiveChars:"IO");
        AllNumericChars = GetCharRange('2', '9');
        AllSpecialChars ="!@#%*()$?+-=";

    }

    public PasswordGenerator(
        int minimumLengthPassword = 15,
        int maximumLengthPassword = 20,
        int minimumLowerCaseChars = 2,
        int minimumUpperCaseChars = 2,
        int minimumNumericChars = 2,
        int minimumSpecialChars = 2)
    {
        if (minimumLengthPassword < 15)
        {
            throw new ArgumentException("The minimumlength is smaller than 15.",
               "minimumLengthPassword");
        }

        if (minimumLengthPassword > maximumLengthPassword)
        {
            throw new ArgumentException("The minimumLength is bigger than the maximum length.",
               "minimumLengthPassword");
        }

        if (minimumLowerCaseChars < 2)
        {
            throw new ArgumentException("The minimumLowerCase is smaller than 2.",
               "minimumLowerCaseChars");
        }

        if (minimumUpperCaseChars < 2)
        {
            throw new ArgumentException("The minimumUpperCase is smaller than 2.",
               "minimumUpperCaseChars");
        }

        if (minimumNumericChars < 2)
        {
            throw new ArgumentException("The minimumNumeric is smaller than 2.",
               "minimumNumericChars");
        }

        if (minimumSpecialChars < 2)
        {
            throw new ArgumentException("The minimumSpecial is smaller than 2.",
               "minimumSpecialChars");
        }

        _minimumNumberOfChars = minimumLowerCaseChars + minimumUpperCaseChars +
                                minimumNumericChars + minimumSpecialChars;

        if (minimumLengthPassword < _minimumNumberOfChars)
        {
            throw new ArgumentException(
               "The minimum length of the password is smaller than the sum" +
               "of the minimum characters of all catagories.",
               "maximumLengthPassword");
        }

        MinimumLengthPassword = minimumLengthPassword;
        MaximumLengthPassword = maximumLengthPassword;

        MinimumLowerCaseChars = minimumLowerCaseChars;
        MinimumUpperCaseChars = minimumUpperCaseChars;
        MinimumNumericChars = minimumNumericChars;
        MinimumSpecialChars = minimumSpecialChars;

        _allAvailableChars =
            OnlyIfOneCharIsRequired(minimumLowerCaseChars, AllLowerCaseChars) +
            OnlyIfOneCharIsRequired(minimumUpperCaseChars, AllUpperCaseChars) +
            OnlyIfOneCharIsRequired(minimumNumericChars, AllNumericChars) +
            OnlyIfOneCharIsRequired(minimumSpecialChars, AllSpecialChars);
    }

    private string OnlyIfOneCharIsRequired(int minimum, string allChars)
    {
        return minimum > 0 || _minimumNumberOfChars == 0 ? allChars : string.Empty;
    }

    public string Generate()
    {
        var lengthOfPassword = _randomSecure.Next(MinimumLengthPassword, MaximumLengthPassword);

        // Get the required number of characters of each catagory and
        // add random charactes of all catagories
        var minimumChars = GetRandomString(AllLowerCaseChars, MinimumLowerCaseChars) +
                        GetRandomString(AllUpperCaseChars, MinimumUpperCaseChars) +
                        GetRandomString(AllNumericChars, MinimumNumericChars) +
                        GetRandomString(AllSpecialChars, MinimumSpecialChars);
        var rest = GetRandomString(_allAvailableChars, lengthOfPassword - minimumChars.Length);
        var unshuffeledResult = minimumChars + rest;

        // Shuffle the result so the order of the characters are unpredictable
        var result = unshuffeledResult.ShuffleTextSecure();
        return result;
    }

    private string GetRandomString(string possibleChars, int lenght)
    {
        var result = string.Empty;
        for (var position = 0; position < lenght; position++)
        {
            var index = _randomSecure.Next(possibleChars.Length);
            result += possibleChars[index];
        }
        return result;
    }

    private static string GetCharRange(char minimum, char maximum, string exclusiveChars ="")
    {
        var result = string.Empty;
        for (char value = minimum; value <= maximum; value++)
        {
            result += value;
        }
        if (!string.IsNullOrEmpty(exclusiveChars))
        {
            var inclusiveChars = result.Except(exclusiveChars).ToArray();
            result = new string(inclusiveChars);
        }
        return result;
    }
}

internal static class Extensions
{
    private static readonly Lazy<RandomSecureVersion> RandomSecure =
        new Lazy<RandomSecureVersion>(() => new RandomSecureVersion());
    public static IEnumerable<T> ShuffleSecure<T>(this IEnumerable<T> source)
    {
        var sourceArray = source.ToArray();
        for (int counter = 0; counter < sourceArray.Length; counter++)
        {
            int randomIndex = RandomSecure.Value.Next(counter, sourceArray.Length);
            yield return sourceArray[randomIndex];

            sourceArray[randomIndex] = sourceArray[counter];
        }
    }

    public static string ShuffleTextSecure(this string source)
    {
        var shuffeldChars = source.ShuffleSecure().ToArray();
        return new string(shuffeldChars);
    }
}

internal class RandomSecureVersion
{
    //Never ever ever never use Random() in the generation of anything that requires true security/randomness
    //and high entropy or I will hunt you down with a pitchfork!! Only RNGCryptoServiceProvider() is safe.
    private readonly RNGCryptoServiceProvider _rngProvider = new RNGCryptoServiceProvider();

    public int Next()
    {
        var randomBuffer = new byte[4];
        _rngProvider.GetBytes(randomBuffer);
        var result = BitConverter.ToInt32(randomBuffer, 0);
        return result;
    }

    public int Next(int maximumValue)
    {
        // Do not use Next() % maximumValue because the distribution is not OK
        return Next(0, maximumValue);
    }

    public int Next(int minimumValue, int maximumValue)
    {
        var seed = Next();

        //  Generate uniformly distributed random integers within a given range.
        return new Random(seed).Next(minimumValue, maximumValue);
    }
}

在你的代码中消耗:

1
2
3
var generator = new PasswordGenerator();
string password = generator.Generate();
Console.WriteLine(password);


我不知道这是否对你有帮助,但当我想生成一个随机的密码时,这也是我要使用的,这个密码也很强。它实现/理解起来既快又简单,而且不像通过上面的成员资格提供商那样杀伤力大…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    private string Token(byte Length) {
        char[] Chars = new char[] {
            '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',
            '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',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
        };
        string String = string.Empty;
        Random Random = new Random();

        for (byte a = 0; a < Length; a++) {
            String += Chars[Random.Next(0, 61)];
        };

        return (String);
    }


埃多克斯1〔0〕怎么样?


对于不允许用户生成密码的系统来说,实际上非常简单:任何密码都和它的长度一样安全。当然,不算那些把它贴在监视器上的人。

您可能希望最大化从中生成密码的字符集。但是限制生成的密码会大大减少搜索空间,从而降低密码的安全性。同样,只有当用户不能选择自己的密码时,这才有效。

如果您同时处理生成的和用户创建的密码,那么显然,所有的赌注都是关闭的。然后,您可能希望以一种方式生成密码,它使用尽可能多的来自不同类的字符,类似于一个强大的用户选择的密码。理想情况下,它应该符合用户创建的密码必须传递的相同约束(如果有的话)。


为什么不在一个数组中填充一些字符,然后随机选取一些字符呢?您可以将它们分组,以确保包括字母、数字和特殊字符。

您还必须选择一个合适的长度,包括每组字符的多少,就这样。我认为你不需要一些复杂的公式。


我会自己使用guid:,并让用户在登录后编辑密码。