asp.netasp.net-mvcasp.net-coreasp.net-core-1.0.net-standard-1.5

Alternative to System.Web.Security.Membership.GeneratePassword in aspnetcore (netcoreapp1.0)


Is there any alternative to System.Web.Security.Membership.GeneratePassword in AspNetCore (netcoreapp1.0).

The easiest way would be to just use a Guid.NewGuid().ToString("n") which is long enough to be worthy of a password but it's not fully random.


Solution

  • Here's a class/method, based on the source of Membership.GeneratePassword of that works on .NET Core:

    public static class Password
    {
        private static readonly char[] Punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray();
    
        public static string Generate(int length, int numberOfNonAlphanumericCharacters)
        {
            if (length < 1 || length > 128)
            {
                throw new ArgumentException(nameof(length));
            }
    
            if (numberOfNonAlphanumericCharacters > length || numberOfNonAlphanumericCharacters < 0)
            {
                throw new ArgumentException(nameof(numberOfNonAlphanumericCharacters));
            }
    
            using (var rng = RandomNumberGenerator.Create())
            {
                var byteBuffer = new byte[length];
    
                rng.GetBytes(byteBuffer);
    
                var count = 0;
                var characterBuffer = new char[length];
    
                for (var iter = 0; iter < length; iter++)
                {
                    var i = byteBuffer[iter] % 87;
    
                    if (i < 10)
                    {
                        characterBuffer[iter] = (char)('0' + i);
                    }
                    else if (i < 36)
                    {
                        characterBuffer[iter] = (char)('A' + i - 10);
                    }
                    else if (i < 62)
                    {
                        characterBuffer[iter] = (char)('a' + i - 36);
                    }
                    else
                    {
                        characterBuffer[iter] = Punctuations[i - 62];
                        count++;
                    }
                }
    
                if (count >= numberOfNonAlphanumericCharacters)
                {
                    return new string(characterBuffer);
                }
    
                int j;
                var rand = new Random();
    
                for (j = 0; j < numberOfNonAlphanumericCharacters - count; j++)
                {
                    int k;
                    do
                    {
                        k = rand.Next(0, length);
                    }
                    while (!char.IsLetterOrDigit(characterBuffer[k]));
    
                    characterBuffer[k] = Punctuations[rand.Next(0, Punctuations.Length)];
                }
    
                return new string(characterBuffer);
            }
        }
    }
    

    I've omitted the do...while loop over the CrossSiteScriptingValidation.IsDangerousString. You can add that back in yourself if you need it.

    You use it like this:

    var password = Password.Generate(32, 12);
    

    Also, make sure you reference System.Security.Cryptography.Algorithms.