Generating Random Passwords with ASP.NET
By Scott Mitchell
Introduction
In one of the consulting projects I'm working on a website that has user accounts (like most every non-trivial Web application).
User accounts for this site can be created in one of two ways: by the user himself, in which case that user provides their
email address and password; or by the user's boss, in which case the boss simply provides his employee's
email address. The system then creates a random password for the employee and emails this information to said
employee. Upon first logging in to the site, the employee must change the random password.
The purpose of this article is to provide a random password generator for ASP.NET. There are a number techniques for creating
a random password, and these techniques are explored, along with source code. Read on to learn more!
Quick and Dirty Random Password Generation Using GUIDs
The simplest random password generation scheme with ASP.NET is to return a portion of a GUID. A GUID is a Globally
Unique ID, a 128-bit number that can be quickly generated with one method call, producing a hexidecimal string that can
be used as a random password. To create a new GUID, use the System.Guid structure's NewGuid() method.
Then, the .ToString() method can be used to create a string version of this. Here's some example code:
' VB.NET
Dim guidResult as String = System.Guid.NewGuid().ToString()
// C#
string guidResult = System.Guid.NewGuid().ToString();
Each time this code is run a new, globally unique number will be generated. Here's the output of this code when run
five times (you can refresh the page and you'll see five new results):
Typically I strip out the hyphens (-) and then return the first n characters of the GUID. To generalize
this technique, let's create a method called GetRandomPasswordUsingGUID(length) that accepts as input
the length of the random password and returns the first length characters of a GUID (with the hyphens removed).
' VB.NET
Public Function GetRandomPasswordUsingGUID(ByVal length as Integer) as String
'Get the GUID
Dim guidResult as String = System.Guid.NewGuid().ToString()
'Remove the hyphens
guidResult = guidResult.Replace("-", String.Empty)
'Make sure length is valid
If length <= 0 OrElse length > guidResult.Length Then
Throw New ArgumentException("Length must be between 1 and " & guidResult.Length)
End If
'Return the first length bytes
Return guidResult.Substring(0, length)
End Function
// C#
public string GetRandomPasswordUsingGUID(int length)
{
// Get the GUID
string guidResult = System.Guid.NewGuid().ToString();
// Remove the hyphens
guidResult = guidResult.Replace("-", string.Empty);
// Make sure length is valid
if (length <= 0 || length > guidResult.Length)
throw new ArgumentException("Length must be between 1 and " + guidResult.Length);
// Return the first length bytes
return guidResult.Substring(0, length);
}
The following shows this output of this method when called with length values of 5, 10, and 15, respectively.
(Again, you can refresh the page and you'll see different random passwords, as each time System.Guid.NewGuid()
is called, a new, unique identifier is created.)
Random password of length 5:652bb
Random password of length 10: d260470cd7
Random password of length 15: f2a8029321d8446
A More Robust Random Password Generator
This nice thing about the GUID approach for creating random passwords is that it is easy to implement and use. However,
it leaves you with no control over the resulting output, and only generates passwords with alphanumeric characters (and
only with letters ranging from a to f). What if you want to impose certain security guidelines, such as requiring a
random password with a certain number of non-alphanumeric characters, or a random password that uses a wider range of
random characters (such as drawing from the entire alphabet)? Or what if, for some reason, you didn't want numbers in
the random password? Or you wanted to make the password case-sensitive (again, with the GUID approach you only have six
letters and they are all lowercase).
A more robust solution would be to create a GeneratePassword(length, numberOfNonAlphanumericCharacters)
password generator that mirrors the behavior of the ASP.NET 2.0 Membership API's method with the same name. This method -
which is what you should use if you're using 2.0 - allows the page developer to specify the random password's length and
the number of non-alphanumeric characters. Furthermore, it uses the RNGCryptoServiceProvider
class, which is a cryptographically strong random number generator. (In English, that means that the algorithm does not suffer
from having characteristics which make it possible to better guess upcoming random numbers based on past random numbers produced.)
If you are stuck in the ASP.NET 1.x world like yours truly, then you'll need to roll your own GeneratePassword()
method. But wait, why duplicate the efforts of the ASP.NET team? Why not just use their code? With a little help from
Reflector this is a cinch. Here is the code for the
Membership.GeneratePassword(length, numberOfNonAlphanumericCharacters) method, along with
a live demo.
' VB.NET
Function GeneratePassword(ByVal length As Integer, _
ByVal numberOfNonAlphanumericCharacters As Integer) As String
'Make sure length and numberOfNonAlphanumericCharacters are valid....
'... checks omitted for brevity ... see live demo for full code ...
Do While True
Dim i As Integer
Dim nonANcount As Integer = 0
Dim buffer1 As Byte() = New Byte(length - 1) {}
'chPassword contains the password's characters as it's built up
Dim chPassword As Char() = New Char(length - 1) {}
'chPunctionations contains the list of legal non-alphanumeric characters
Dim chPunctuations as Char() = "!@@$%^^*()_-+=[{]};:>|./?".ToCharArray()
'Get a cryptographically strong series of bytes
Dim rng as New System.Security.Cryptography.RNGCryptoServiceProvider
rng.GetBytes(buffer1)
For i = 0 To length - 1
'Convert each byte into its representative character
Dim rndChr As Integer = (buffer1(i) Mod 87)
If (rndChr < 10) Then
chPassword(i) = Convert.ToChar(Convert.ToUInt16(48 + rndChr))
Else
If (rndChr < 36) Then
chPassword(i) = Convert.ToChar(Convert.ToUInt16((65 + rndChr) - 10))
Else
If (rndChr < 62) Then
chPassword(i) = Convert.ToChar(Convert.ToUInt16((97 + rndChr) - 36))
Else
chPassword(i) = chPunctuations(rndChr - 62)
nonANcount += 1
End If
End If
End If
Next
If nonANcount < numberOfNonAlphanumericCharacters Then
Dim rndNumber As New Random
For i = 0 To (numberOfNonAlphanumericCharacters - nonANcount) - 1
Dim passwordPos As Integer
Do
passwordPos = rndNumber.Next(0, length)
Loop While Not Char.IsLetterOrDigit(chPassword(passwordPos))
chPassword(passwordPos) = _
chPunctuations(rndNumber.Next(0, chPunctuations.Length))
Next
End If
Return New String(chPassword)
Loop
End Function
Note: I tweaked the GetPassword() method in that I removed some of the potentially dangerous non-alphanumeric
characters (namely # and &). ASP.NET 2.0 does a check to ensure that the randomly generated password
can't be used in a cross-site scripting attack, and the characters it checks for is <, #, and
&. I just removed these to avoid needing to include the code for the XSS check...
Conclusion
In this article we examined two techniques for generating random passwords using ASP.NET. In the first technique we used a
GUID, stripped out the hyphens, and then returned the first length characters of the GUID. This approach is a quick
and easy way to generate a random password. However, it lacks in sophistication in that its potential pool of characters is
rather limited (a-f and 0-9).
A more robust and elegant random password generator can be seen in ASP.NET 2.0's Membership.GeneratePassword()
method. If you are using 2.0 most definitely take advantage of this method. If you are still using ASP.NET 1.x, however, you'll
need to create your own password generator if you need an approach more robust than the GUID approach first examined.
In this article we saw how to 'copy' 2.0's GeneratePassword() method using Reflector.