Kids, Code, and Computer Science Magazine

Create a Random Password Generator with C#

Christiaan Colen on Flickr

This project, shows you how to create your own random password generator in the C# programming language.

This version of the article includes the full code, as well as a link to see this code in action where you can tweak the code to see what happens. This code generates random strong passwords that meet the OWASP recommendations.

If you don’t know C#, or don’t program, don’t worry. This article also is a way to learn how to read code which is an important skill for programmers to learn. To read code, you first have to understand any rules and requirements then look into how code is structured to meet those rules and requirements.

When you read code, ask yourself at least two questions as you read:

  • What is the code supposed to do?
  • How does the code do what it’s supposed to do?

The code that follows uses bold to help you map methods to their use elsewhere in the code.

Password Rules and Requirements

Passwords we create must meet at least 3 of these complexity rules with at least…

  • 1 uppercase character (A-Z)
  • 1 lowercase character (a-z)
  • 1 digit (0-9)
  • 1 special character (punctuation) — do not forget to treat space as special characters too

In addition, no more than…

  • 10 characters (I’ve set it at 8 to satisfy some old password systems, but you can change this)
  • 128 characters
  • 2 identical characters in a row (so 11 is okay but 111 is not allowed)

Create our Program Method

To meet our password rules and requirements, we will create a single method called Program which will call other methods to build and test our password.

There also will be a list of characters to randomly choose from to create our password.

We will add options for which password rules we would like to enforce on each request, so these will be parameters in the Program constructor. The method will need to return the password as a string despite including numbers.

Numbers 1-4 in the code example describe how our Program method works:

  • First, we include any code libraries and system resources we need to use (lines 3-5).
  • Next, our Main() method is called when our software runs (line 9).
  • Within the Main() method, next we call the PasswordGeneratorSettings method (line 18) to create an object and assign its result to a variable called settings. The settings variable is defined by passing a number of password-related variables (lines 11-16) to the PasswordGeneratorSettings method, for example, whether or not to include uppercase or special characters.
  • Finally, our Main() method takes the result of our settings variable and tests that the password we get back from other methods meets our requirements (lines 20-35).
  • While this might sound complicated, look at the code and play a game of find the code block by matching method names in the Program method to other methods in our code, for example, find the PasswordGeneratorSettings method. Think of methods as engines and the values we pass to them as fuel to be processed.

    Also pay attention to the word return. In most programming languages return is how you return the result after a method is done processing data handed to it. If someone hands you paper and a pen and asks you to write the word cat, and you do so, then you return the paper with the word cat written on it. In the Main() code block, data is returned with Console.WriteLine(password) (line 37) which means write the result of the Main() method, your password, to your computer screen or console.

    Define and Create our Password

    If the Program method is our main code block and runs when our software application runs, the other methods in our code are used to define, create, and test our shiny new password.

    PasswordGeneratorSettings (line 41) creates all the settings for our password — whether or not to include uppercase characters, for example — then tests the length of our password is valid and generates an error message if our password is too short or too long.

    PasswordGenerator (line 103) creates the password based on the rules set in the Program method, for example, the maximum number of identical characters allowed. YY is okay but YYY is not.

    The PasswordIsValid method (line 143) checks the password created by the PasswordGenerator method meets our requirements.

    Here is our code to read. To help you read along, key lines are in bold. You also might want to print out this page then use a pen or pencil to mark up the code.

    //Written by Paul Seal. Licensed under MIT. Free for private and commercial uses.
    
    using System;
    using System.Text.RegularExpressions;
    using System.Text;
                        
    public class Program
    {
        public static void Main()
        {
    	const int MAXIMUM_PASSWORD_ATTEMPTS = 10000;
            bool includeLowercase = true;
            bool includeUppercase = true;
            bool includeNumeric = true;
    		bool includeSpecial = false;
            int lengthOfPassword  = 16;
            
    		PasswordGeneratorSettings settings = new PasswordGeneratorSettings(includeLowercase, includeUppercase, includeNumeric, includeSpecial, lengthOfPassword);
    		string password;
    		if (!settings.IsValidLength())
    		{
    			password = settings.LengthErrorMessage();
    		}
    		else
    		{
    			int passwordAttempts = 0;
    			do
    			{
    				password = PasswordGenerator.GeneratePassword(settings);
    				passwordAttempts++;
    			}
    			while (passwordAttempts < MAXIMUM_PASSWORD_ATTEMPTS && !PasswordGenerator.PasswordIsValid(settings, password));
    			
    			password = PasswordGenerator.PasswordIsValid(settings, password) ? password : "Try again";
    		}
            
            Console.WriteLine(password);
        }
    }
    
    public class PasswordGeneratorSettings
    {
    	const string LOWERCASE_CHARACTERS = "abcdefghijklmnopqrstuvwxyz";
    	const string UPPERCASE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    	const string NUMERIC_CHARACTERS = "0123456789";
    	const string SPECIAL_CHARACTERS = @"!#$%&*@\";
    	const int PASSWORD_LENGTH_MIN = 8;
    	const int PASSWORD_LENGTH_MAX = 128;
    	
    	public bool IncludeLowercase {get; set; }
    	public bool IncludeUppercase { get; set; }
    	public bool IncludeNumbers { get; set; }
    	public bool IncludeSpecial { get; set; }
    	public int PasswordLength { get; set; }
    	public string CharacterSet { get; set; }
    	public int MaximumAttempts { get; set; }
    	
    	public PasswordGeneratorSettings(bool includeLowercase, bool includeUppercase, bool includeNumbers, bool includeSpecial, int passwordLength)
    	{
    		IncludeLowercase = includeLowercase;
    		IncludeUppercase = includeUppercase;
    		IncludeNumbers = includeNumbers;
    		IncludeSpecial = includeSpecial;
    		PasswordLength = passwordLength;
    		
    		StringBuilder characterSet = new StringBuilder();
    		
    		if (includeLowercase)
    		{
    			characterSet.Append(LOWERCASE_CHARACTERS);
    		}
    		
    		if (includeUppercase)
    		{
    			characterSet.Append(UPPERCASE_CHARACTERS);
    		}
    		
    		if (includeNumbers)
    		{
    			characterSet.Append(NUMERIC_CHARACTERS);
    		}
    		
    		if (includeSpecial)
    		{
    			characterSet.Append(SPECIAL_CHARACTERS);
    		}
    		
    		CharacterSet = characterSet.ToString();
    	}
    	
    	public bool IsValidLength()
    	{
    		return PasswordLength >= PASSWORD_LENGTH_MIN && PasswordLength <= PASSWORD_LENGTH_MAX;
    	}
    	
    	public string LengthErrorMessage()
    	{
    		return string.Format("Password length must be between {0} and {1} characters", PASSWORD_LENGTH_MIN, PASSWORD_LENGTH_MAX);
    	}
    }
    
    
    public static class PasswordGenerator
    {
    	
    	/// <summary>
    	/// Generates a random password based on the rules passed in the settings parameter
    	/// </summary>
    	/// <param name="settings">Password generator settings object</param>
    	/// <returns>Password or try again</returns>
    	public static string GeneratePassword(PasswordGeneratorSettings settings)
    	{
    		const int MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS = 2;
    		char[] password = new char[settings.PasswordLength];
    		int characterSetLength = settings.CharacterSet.Length;
    		
    		System.Random random = new System.Random();
    		for (int characterPosition = 0; characterPosition < settings.PasswordLength; characterPosition++)
    		{
    			password[characterPosition] = settings.CharacterSet[random.Next(characterSetLength - 1)];
    			
    			bool moreThanTwoIdenticalInARow =
    				characterPosition > MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS
    				&& password[characterPosition] == password[characterPosition - 1]
    				&& password[characterPosition - 1] == password[characterPosition - 2];
    			
    			if (moreThanTwoIdenticalInARow)
    			{
    				characterPosition--;
    			}
    		}
    		
    		return string.Join(null, password);
    	}
    	
    	
    	/// <summary>
    	/// When you give it a password and some settings, it validates the password against the settings.
    	/// </summary>
    	/// <param name="settings">Password settings</param>
    	/// <param name="password">Password to test</param>
    	/// <returns>True or False to say if the password is valid or not</returns>
    	public static bool PasswordIsValid(PasswordGeneratorSettings settings, string password)
    	{
    		const string REGEX_LOWERCASE = @"[a-z]";
    		const string REGEX_UPPERCASE = @"[A-Z]";
    		const string REGEX_NUMERIC = @"[\d]";
    		const string REGEX_SPECIAL = @"([!#$%&*@\\])+";
    		
    		bool lowerCaseIsValid = !settings.IncludeLowercase || (settings.IncludeLowercase && Regex.IsMatch(password, REGEX_LOWERCASE));
    		bool upperCaseIsValid = !settings.IncludeUppercase || (settings.IncludeUppercase && Regex.IsMatch(password, REGEX_UPPERCASE));
    		bool numericIsValid = !settings.IncludeNumbers || (settings.IncludeNumbers && Regex.IsMatch(password, REGEX_NUMERIC));
    		bool symbolsAreValid = !settings.IncludeSpecial || (settings.IncludeSpecial && Regex.IsMatch(password, REGEX_SPECIAL));
    		
    		return lowerCaseIsValid && upperCaseIsValid && numericIsValid && symbolsAreValid;
    	}
    }
    

    Test Our Code

    Be sure to visit the online article if you want to see the code in action. You can change settings in the Program method, for example, and see how it changes the password generated by this code.

    Learn More

    Code on DotNetFiddle

    Press the Run button at the top of the page and random password appears at bottom pane below the code.
    https://dotnetfiddle.net/Y9VnaX

    How to Create a Random Password Generator in C#

    http://www.codeshare.co.uk/blog/how-to-create-a-random-password-generator-in-c/
    https://www.youtube.com/watch?v=TZ-ppATOCYI
    https://github.com/prjseal/PasswordGenerator
    https://www.nuget.org/packages/PasswordGenerator
    https://dotnetfiddle.net/U8TLQA

    The Open Web Application Security Project (OWASP)

    https://www.owasp.org
    https://www.owasp.org/index.php/Authentication_Cheat_Sheet


    Also In The December 2016 Issue

    Hour of Code and EU Code Week are events designed to introduce kids, young adults, and others to programming and computer science.

    Real life treasure hunts are a way to get outdoors, learn map skills, and have fun finding hidden caches near you.

    A trainable puppy plus treats plus technology equals a dog that can send selfies. Here's how.

    An app to help kids remember important stuff like feed your pets, brush your teeth, and smile.

    These books include lots of great projects to work on by yourself or with others, from Scratch and Minecraft to fun maker space projects.

    The mBot robotics kit is an excellent comparatively low-cost way to begin working with robots.

    There are maybe a bazillion Raspberry Pi projects online. Here are really fun projects plus links to find more.

    The Wayback Machine lets you travel back in time to see old websites. Plus the Internet Archive has thousands of vintage games, software, books, and more.

    Eating dog food doesn't sound like much fun but it's an important part of creating software.

    The ability to identify patterns, decompose large problems into small parts, develop algorithms to solve problems, and generalize to find solutions.

    To celebrate this wonderful time of the year, let’s create some holiday music using Sonic Pi on our Raspberry Pi.

    This project shows how to use the pygame code library to move simple animations with the Python programming language.

    This project, shows you how to create your own random password generator in the C# programming language.

    These projects mix science and technology in interesting ways. Sewing and electronics, for example, is a different way to learn about electronics.

    Links from the bottom of all the December 2016 articles, collected in one place for you to print, share, or bookmark.

    Interesting stories about computer science, software programming, and technology for December 2016.

    What sounds like a country western dance actually is an efficient way to sort large sets of data randomly.