Click here to Skip to main content
11,925,849 members (62,240 online)
Click here to Skip to main content
Add your own
alternative version


129 bookmarked

A C# Password Generator

, 17 Aug 2003
Rate this:
Please Sign up or sign in to vote.
An article on implementing a simple password generator class in C#


This article illustrates how to create a very simple password generator using C#. Password generators are useful in many applications:

  • Registration/membership systems for Web sites
  • Auto-creation of passwords according to a specified rule
  • Securing application-specific data

The PasswordGenerator class is fairly simple. It exposes several properties that control how the password will be generated.

  • Exclusions: Specifies the set of characters to exclude in password generation.
  • Minimum: Specifies the minimum length of the generated password.
  • Maximum: Specifies the maximum length of the generated password.
  • ConsecutiveCharacters: Controls generation of consecutive characters in the generated password.
  • RepeatingCharacters: Controls generation of repeating characters in the generated password.
  • ExcludeSymbols: Excludes symbols from the set of characters used to generate the password

After setting your desired properties, call the Generate() method to create your new password.

namespace WorkingCode.CodeProject.PwdGen
    using System;
    using System.Security.Cryptography;
    using System.Text;

    public class PasswordGenerator
        public PasswordGenerator() 
            this.Minimum               = DefaultMinimum;
            this.Maximum               = DefaultMaximum;
            this.ConsecutiveCharacters = false;
            this.RepeatCharacters      = true;
            this.ExcludeSymbols        = false;
            this.Exclusions            = null;

            rng = new RNGCryptoServiceProvider();
        protected int GetCryptographicRandomNumber(int lBound, int uBound)
            // Assumes lBound >= 0 && lBound < uBound
            // returns an int >= lBound and < uBound
            uint urndnum;   
            byte[] rndnum = new Byte[4];   
            if (lBound == uBound-1)  
                // test for degenerate case where only lBound can be returned
                return lBound;
            uint xcludeRndBase = (uint.MaxValue -
                urndnum = System.BitConverter.ToUInt32(rndnum,0);      
            } while (urndnum >= xcludeRndBase);   
            return (int)(urndnum % (uBound-lBound)) + lBound;

        protected char GetRandomCharacter()
            int upperBound = pwdCharArray.GetUpperBound(0);

            if ( true == this.ExcludeSymbols )
                upperBound = PasswordGenerator.UBoundDigit;

            int randomCharPosition = GetCryptographicRandomNumber(
                pwdCharArray.GetLowerBound(0), upperBound);

            char randomChar = pwdCharArray[randomCharPosition];

            return randomChar;
        public string Generate()
            // Pick random length between minimum and maximum   
            int pwdLength = GetCryptographicRandomNumber(this.Minimum,

            StringBuilder pwdBuffer = new StringBuilder();
            pwdBuffer.Capacity = this.Maximum;

            // Generate random characters
            char lastCharacter, nextCharacter;

            // Initial dummy character flag
            lastCharacter = nextCharacter = '\n';

            for ( int i = 0; i < pwdLength; i++ )
                nextCharacter = GetRandomCharacter();

                if ( false == this.ConsecutiveCharacters )
                    while ( lastCharacter == nextCharacter )
                        nextCharacter = GetRandomCharacter();

                if ( false == this.RepeatCharacters )
                    string temp = pwdBuffer.ToString();
                    int duplicateIndex = temp.IndexOf(nextCharacter);
                    while ( -1 != duplicateIndex )
                        nextCharacter = GetRandomCharacter();
                        duplicateIndex = temp.IndexOf(nextCharacter);

                if ( ( null != this.Exclusions ) )
                    while ( -1 != this.Exclusions.IndexOf(nextCharacter) )
                        nextCharacter = GetRandomCharacter();

                lastCharacter = nextCharacter;

            if ( null != pwdBuffer )
                return pwdBuffer.ToString();
                return String.Empty;
        public string Exclusions
            get { return this.exclusionSet;  }
            set { this.exclusionSet = value; }

        public int Minimum
            get { return this.minSize; }
                this.minSize = value;
                if ( PasswordGenerator.DefaultMinimum > this.minSize )
                    this.minSize = PasswordGenerator.DefaultMinimum;

        public int Maximum
            get { return this.maxSize; }
                this.maxSize = value;
                if ( this.minSize >= this.maxSize )
                    this.maxSize = PasswordGenerator.DefaultMaximum;

        public bool ExcludeSymbols
            get { return this.hasSymbols; }
            set	{ this.hasSymbols = value;}

        public bool RepeatCharacters
            get { return this.hasRepeating; }
            set	{ this.hasRepeating = value;}

        public bool ConsecutiveCharacters
            get { return this.hasConsecutive; }
            set	{ this.hasConsecutive = value;}

        private const int DefaultMinimum = 6;
        private const int DefaultMaximum = 10;
        private const int UBoundDigit    = 61;

        private RNGCryptoServiceProvider    rng;
        private int 			minSize;
        private int 			maxSize;
        private bool			hasRepeating;
        private bool			hasConsecutive;
        private bool            hasSymbols;
        private string          exclusionSet;
        private char[] pwdCharArray = "abcdefghijklmnopqrstuvwxyzABCDEFG" +
            "HIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+[]{}\\|;:'\",<" + 

The previous version of this class was intended for use in a much larger project (I will be publishing articles on various components of that project soon.). Due to many factors, that code was rushed and proved to be inefficient. In fact, I wish I could go back in time and unpublish it! While this version is definitely better, there is still room for improvement. The generation algorithm can still be optimized. Also, it would be interesting to use regular expressions to both define and validate the passwords we wish to generate. I would have done this, but it's been a long time since I wrote a parser. Maybe for the next version...

In previous articles, I have used the NAnt tool as my build solution. Unfortunately, that team has not produced a stable release that integrates NUnit 2.0. I COULD get the source from the CVS tree, but I'm way too lazy for that. Instead, I have decided to go back to Visual Studio .NET as my development environment. I'm also getting used to test-driven development with NUnit 2.0. If you aren't using this tool for unit testing, I highly recommend you give it a try Its use of attributes and reflection to specify test suites, test fixtures and tests, and is quite remarkable and easy to use. I've included my unit test fixture with the source code. Also, try the NUnit Addin for Visual Studio .NET; it's very handy for running your tests within the IDE.

The demo project is a simple Windows Forms UI that allows one to configure the password generator's properties. I must say that while VS.NET is fairly complete and powerful, I just don't like the feel of the forms designer. However, it definitely does the job.

Many thanks to Mike Asher and Julian Roberts for their feedback on the first version of the password generator. Julian was kind enough to test the code in an ASP.NET project and confirmed that it performs much better. Also, I reverted to my old C++ bracing style just to make Nish happy...hope you appreciate the sacrifice! Smile | :)

Change Log

Version 1.2

  • Updated for .NET Framework 1.1
  • Removed FirstCharacter and LastCharacter properties; Exclusions works across all characters
  • Replaced Password property with Generate() method
  • Removed PwdMaskFlags; use Exclusions property and/or ExcludeSymbols property
  • Used RNGCryptoServiceProvider instead of Random for random number generation
  • Updated demo application

Perfection (in design) is achieved not when there is nothing more to add, but rather when there is nothing more to take away. - Antoine de Saint-Exupéry

Version 1.1

  • Improved password generation algorithm

Version 1.0

  • Initial version


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Kevin Stewart
Web Developer
United States United States
Kevin is a software development manager for a small consumer-oriented company in SoHo, NY. He is technology and platform agnostic having worked on PCs, Macintosh and various forms of Unix and Linux. His programming knowledge includes several languages, including C/C++, Java and C#. In the rare moments when his head is not buried in the latest tech book purchase from Amazon, Kevin enjoys spending time with his wife Donna and their dog Kirby.

You may also be interested in...

Comments and Discussions

QuestionLicense for use of the above code Pin
monicanahar10-Apr-14 2:59
membermonicanahar10-Apr-14 2:59 
GeneralBug with pwdCharArray Pin
quandary2-Aug-12 6:29
memberquandary2-Aug-12 6:29 
GeneralNice work Pin
RockingDownTheHighway3-Feb-11 5:55
memberRockingDownTheHighway3-Feb-11 5:55 
QuestionBug in Generate() method Pin
geoffbishop@gmail.com15-Dec-08 10:48
membergeoffbishop@gmail.com15-Dec-08 10:48 
QuestionBug when exact password size requested Pin
geoffbishop@gmail.com15-Dec-08 10:09
membergeoffbishop@gmail.com15-Dec-08 10:09 
AnswerRe: Bug when exact password size requested Pin
Member 235774024-Feb-09 8:34
memberMember 235774024-Feb-09 8:34 
GeneralException thrown Pin
thom_ek29-May-08 3:49
memberthom_ek29-May-08 3:49 
GeneralPronounceable passwords Pin
marschills16-Nov-07 12:29
membermarschills16-Nov-07 12:29 
GeneralRe: Pronounceable passwords Pin
Kevin Stewart16-Nov-07 19:30
memberKevin Stewart16-Nov-07 19:30 
GeneralOverriding the constructor Pin
Spam Basket9-Mar-07 9:36
memberSpam Basket9-Mar-07 9:36 
GeneralHere's a VB Implementation... Pin
code-frog31-Jan-07 8:59
membercode-frog31-Jan-07 8:59 
Here's a VB implementation of the same. I just ran Kevin's code through a VB converter. Obviously, Kevin retains the copyright and the work. I did not lift a finger to make this work. I did use InstantVB from Tangible Software though. I'm a C# programmer but have a client that requested I work in VB I cannot think VB at all. It just doesn't come naturally so I bought InstantVB. I'm coding in C# and using Instant VB to migrate the code. So far it's been beautiful.

One word of advice. Make sure your min is less than your max or you get a div by zero error in line 36. No big deal. I didn't even debug it. Just played along with it. This also allows for a more random generation.
' This conversion is Copyright Kevin Stewart. He retains all rights.
' This code is provided as is with no warranty and certainly no
' support or obligation there-of from Kevin Stewart.

Imports Microsoft.VisualBasic
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Security.Cryptography
Imports System.Text
Public Class PasswordGenerator
    Public Sub New()
        Me.Minimum = DefaultMinimum
        Me.Maximum = DefaultMaximum
        Me.ConsecutiveCharacters = False
        Me.RepeatCharacters = True
        Me.ExcludeSymbols = False
        Me.Exclusions = Nothing
        rng = New RNGCryptoServiceProvider()
    End Sub
    Protected Function GetCryptographicRandomNumber(ByVal lBound As Integer, ByVal uBound As Integer) As Integer
        ' Assumes lBound >= 0 && lBound < uBound
        ' returns an int >= lBound and < uBound
        Dim urndnum As UInteger
        Dim rndnum As Byte() = New Byte(3) {}
        If lBound = uBound - 1 Then
            ' test for degenerate case where only lBound can be returned   
            Return lBound
        End If
        Dim xcludeRndBase As UInteger = (UInteger.MaxValue - (UInteger.MaxValue Mod CUInt(uBound - lBound)))
        'uint xcludeRndBase = (uint.MaxValue - (uint.MaxValue % (uint)(uBound - lBound)));

            urndnum = System.BitConverter.ToUInt32(rndnum, 0)
        Loop While urndnum >= xcludeRndBase
        Return CInt(Fix(urndnum Mod (uBound - lBound))) + lBound
    End Function
    Protected Function GetRandomCharacter() As Char
        Dim upperBound As Integer = pwdCharArray.GetUpperBound(0)
        If True = Me.ExcludeSymbols Then
            upperBound = PasswordGenerator.UBoundDigit
        End If
        Dim randomCharPosition As Integer = GetCryptographicRandomNumber(pwdCharArray.GetLowerBound(0), upperBound)
        Dim randomChar As Char = pwdCharArray(randomCharPosition)
        Return randomChar
    End Function
    Public Function Generate() As String
        ' Pick random length between minimum and maximum   
        Dim pwdLength As Integer = GetCryptographicRandomNumber(Me.Minimum, Me.Maximum)
        Dim pwdBuffer As StringBuilder = New StringBuilder()
        pwdBuffer.Capacity = Me.Maximum
        ' Generate random characters
        Dim lastCharacter, nextCharacter As Char
        ' Initial dummy character flag
        nextCharacter = ControlChars.Lf
        lastCharacter = nextCharacter
        For i As Integer = 0 To pwdLength - 1
            nextCharacter = GetRandomCharacter()
            If False = Me.ConsecutiveCharacters Then
                Do While lastCharacter = nextCharacter
                    nextCharacter = GetRandomCharacter()
            End If
            If False = Me.RepeatCharacters Then
                Dim temp As String = pwdBuffer.ToString()
                Dim duplicateIndex As Integer = temp.IndexOf(nextCharacter)
                Do While -1 <> duplicateIndex
                    nextCharacter = GetRandomCharacter()
                    duplicateIndex = temp.IndexOf(nextCharacter)
            End If
            If (Not Nothing Is Me.Exclusions) Then
                Do While -1 <> Me.Exclusions.IndexOf(nextCharacter)
                    nextCharacter = GetRandomCharacter()
            End If
            lastCharacter = nextCharacter
        Next i
        If Not Nothing Is pwdBuffer Then
            Return pwdBuffer.ToString()
            Return String.Empty
        End If
    End Function
    Public Property Exclusions() As String
            Return Me.exclusionSet
        End Get
        Set(ByVal value As String)
            Me.exclusionSet = Value
        End Set
    End Property
    Public Property Minimum() As Integer
            Return Me.minSize
        End Get
        Set(ByVal value As Integer)
            Me.minSize = Value
            If PasswordGenerator.DefaultMinimum > Me.minSize Then
                Me.minSize = PasswordGenerator.DefaultMinimum
            End If
        End Set
    End Property
    Public Property Maximum() As Integer
            Return Me.maxSize
        End Get
        Set(ByVal value As Integer)
            Me.maxSize = Value
            If Me.minSize >= Me.maxSize Then
                Me.maxSize = PasswordGenerator.DefaultMaximum
            End If
        End Set
    End Property
    Public Property ExcludeSymbols() As Boolean
            Return Me.hasSymbols
        End Get
        Set(ByVal value As Boolean)
            Me.hasSymbols = Value
        End Set
    End Property
    Public Property RepeatCharacters() As Boolean
            Return Me.hasRepeating
        End Get
        Set(ByVal value As Boolean)
            Me.hasRepeating = Value
        End Set
    End Property
    Public Property ConsecutiveCharacters() As Boolean
            Return Me.hasConsecutive
        End Get
        Set(ByVal value As Boolean)
            Me.hasConsecutive = Value
        End Set
    End Property
    Private Const DefaultMinimum As Integer = 6
    Private Const DefaultMaximum As Integer = 10
    Private Const UBoundDigit As Integer = 61
    Private rng As RNGCryptoServiceProvider
    Private minSize As Integer
    Private maxSize As Integer
    Private hasRepeating As Boolean
    Private hasConsecutive As Boolean
    Private hasSymbols As Boolean
    Private exclusionSet As String
    Private pwdCharArray As Char() = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+[]{}\|;:'"",<.>/?".ToCharArray()
End Class

GeneralRe: Here's a VB Implementation... Pin
Kevin Stewart7-Feb-07 15:28
memberKevin Stewart7-Feb-07 15:28 
GeneralRe: Here's a VB Implementation... Pin
code-frog8-Feb-07 3:38
membercode-frog8-Feb-07 3:38 
GeneralRe: Here's a VB Implementation... Pin
code-frog8-Feb-07 3:40
membercode-frog8-Feb-07 3:40 
GeneralI threw you a 5... Pin
code-frog30-Oct-06 19:43
membercode-frog30-Oct-06 19:43 
GeneralRe: I threw you a 5... Pin
Kevin Stewart3-Nov-06 3:02
memberKevin Stewart3-Nov-06 3:02 
QuestionCopyright Release? Pin
tgiphil4-Oct-05 19:14
membertgiphil4-Oct-05 19:14 
AnswerRe: Copyright Release? Pin
Kevin Stewart5-Oct-05 5:42
memberKevin Stewart5-Oct-05 5:42 
GeneralNice class Pin
Jan R Hansen17-May-05 21:46
memberJan R Hansen17-May-05 21:46 
GeneralRe: Nice class Pin
Danny Crowell27-Jun-05 13:11
memberDanny Crowell27-Jun-05 13:11 
GeneralpwdCharArray Pin
aztracker121-Mar-05 9:41
memberaztracker121-Mar-05 9:41 
GeneralInfinite Loop using RepeatCharacters as false Pin
frihani7-Feb-05 12:34
memberfrihani7-Feb-05 12:34 
GeneralAlternative Pin
smallguy16-Jun-04 9:04
membersmallguy16-Jun-04 9:04 
GeneralRe: Alternative Pin
Kevin Stewart16-Jun-04 9:30
memberKevin Stewart16-Jun-04 9:30 
GeneralRe: Alternative Pin
smallguy16-Jun-04 12:01
membersmallguy16-Jun-04 12:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151126.1 | Last Updated 18 Aug 2003
Article Copyright 2002 by Kevin Stewart
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid