Generating Random Passwords

2019-01-03 11:41发布

When a user on our site looses his password and heads off to the Lost Password page we need to give him a new temporary password. I don't really mind how random this is, or if it matches all the "needed" strong password rules, all I want to do is give them a password that they can change later.

The application is a Web application written in C#. so I was thinking of being mean and going for the easy route of using part of a Guid. i.e.

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

Suggesstions? thoughts?

21条回答
贪生不怕死
2楼-- · 2019-01-03 12:20

I know that this is an old thread, but I have what might be a fairly simple solution for someone to use. Easy to implement, easy to understand, and easy to validate.

Consider the following requirement:

I need a random password to be generated which has at least 2 lower-case letters, 2 upper-case letters and 2 numbers. The password must also be a minimum of 8 characters in length.

The following regular expression can validate this case:

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

It's outside the scope of this question - but the regex is based on lookahead/lookbehind and lookaround.

The following code will create a random set of characters which match this requirement:

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

}

To meet the above requirement, simply call the following:

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

The code starts with an invalid character ("!") - so that the string has a length into which new characters can be injected.

It then loops from 1 to the # of lowercase characters required, and on each iteration, grabs a random item from the lowercase list, and injects it at a random location in the string.

It then repeats the loop for uppercase letters and for numerics.

This gives you back strings of length = lowercase + uppercase + numerics into which lowercase, uppercase and numeric characters of the count you want have been placed in a random order.

查看更多
走好不送
3楼-- · 2019-01-03 12:24

I created this method similar to the available in the membership provider. This is usefull if you don't want to add the web reference in some applications.

It works great.

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;
    }
查看更多
Root(大扎)
4楼-- · 2019-01-03 12:25

Here's how I generate random tokens:

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

It's been noted that as this returns a base-64 string, the output length is always a multiple of 4, with the extra space using = as a padding character. The length parameter specifies the length of the byte buffer, not the output string (and is therefore perhaps not the best name for that parameter, now I think about it). This controls how many bytes of entropy the password will have. However, because base-64 uses a 4-character block to encode each 3 bytes of input, if you ask for a length that's not a multiple of 3, there will be some extra "space", and it'll use = to fill the extra.

If you don't like using base-64 strings for any reason, you can replace the Convert.ToBase64String() call with either a conversion to regular string, or with any of the Encoding methods; eg. Encoding.UTF8.GetString(tokenBuffer) - just make sure you pick a character set that can represent the full range of values coming out of the RNG, and that produces characters that are compatible with wherever you're sending or storing this. Using Unicode, for example, tends to give a lot of Chinese characters. Using base-64 guarantees a widely-compatible set of characters, and the characteristics of such a string shouldn't make it any less secure as long as you use a decent hashing algorithm.

查看更多
我命由我不由天
5楼-- · 2019-01-03 12:26

I've always been very happy with the password generator built-in to KeePass. Since KeePass is a .Net program, and open source, I decided to dig around the code a bit. I ended up just referncing KeePass.exe, the copy provided in the standard application install, as a reference in my project and writing the code below. You can see how flexible it is thanks to KeePass. You can specify length, which characters to include/not include, etc...

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();
    }
查看更多
做个烂人
6楼-- · 2019-01-03 12:27

On my website I use this method:

    //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 _SymbolsAll for your array list.

查看更多
迷人小祖宗
7楼-- · 2019-01-03 12:28

Here Is what i put together quickly.

    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;
    }
查看更多
登录 后发表回答