|
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)));
Do
rng.GetBytes(rndnum)
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()
Loop
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)
Loop
End If
If (Not Nothing Is Me.Exclusions) Then
Do While -1 <> Me.Exclusions.IndexOf(nextCharacter)
nextCharacter = GetRandomCharacter()
Loop
End If
pwdBuffer.Append(nextCharacter)
lastCharacter = nextCharacter
Next i
If Not Nothing Is pwdBuffer Then
Return pwdBuffer.ToString()
Else
Return String.Empty
End If
End Function
Public Property Exclusions() As String
Get
Return Me.exclusionSet
End Get
Set(ByVal value As String)
Me.exclusionSet = Value
End Set
End Property
Public Property Minimum() As Integer
Get
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
Get
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
Get
Return Me.hasSymbols
End Get
Set(ByVal value As Boolean)
Me.hasSymbols = Value
End Set
End Property
Public Property RepeatCharacters() As Boolean
Get
Return Me.hasRepeating
End Get
Set(ByVal value As Boolean)
Me.hasRepeating = Value
End Set
End Property
Public Property ConsecutiveCharacters() As Boolean
Get
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
|
|
|
|
|
code-frog,
I felt the same way about VB.Net. I've been a C-family developer for a long time and just couldn't warm up to VB (same thing for AppleScript, now that I develop on a Mac). Now, I tend to code in Ruby. I am glad that you were able to convert and use my code without any issue. I guess I'm curious; were you not able to call the C# implementation from VB.Net? "Language independence" used to be one of the big .NET selling points. To me, PasswordGenerator could just be treated as a class in a library that you could call from the VB code. In the end, it doesn't matter but I was curious if your client dictated that ALL code even 3rd party stuff be in VB. Thanks!
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
I'm not actually sealing up this project. They need the code from top to bottom as their in-house developers will pick as much of what I do as they can. So everything needs to be in VB with source so that changes can be made. Your code could be stuck in a library but we aren't using it for passwords. We are using it to generate some random strings to guarantee a unique string when merged with some other stuff. So it's been extended a bit.
I provided the conversion for a few reasons. One I had a business reason to do it, no C# permitted. Two it seemed pretty cool to me that I could convert C# to VB so casually and that it would work. The entire conversion process for your class was under 2 seconds and I've migrated entire projects (windowless code I've written for tracking users, cookies, database wrappers) pretty much as fast. Point->Copy->Click->Paste and Voila. It just works.
Aside from that you are right, stuff it into an assembly and don't look back unless... that isn't an option and in the software world when do project managers actually make things easy?
|
|
|
|
|
One other reason...
I think it's a pretty fascinating way to compare the languages. Take two pieces of code that functionally do the same thing one in C# one in VB and look at the differences. If you are on the edge of using C# or VB and want to see some comparisons there is now a short concise example burried away in your article. For me when I look at the VB conversion my stomach starts to cramp but hey... to each their own. It might help someone on the edge of indecision.
|
|
|
|
|
Other than that just saying thanks for the article. Insightful and handy and ... and ... and...
|
|
|
|
|
Thank you so much! I appreciate that!
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
Kevin,
What's the copyright status of this class? I'd like to use it, rather than re-invent the wheel.
|
|
|
|
|
The copyright status is (c) 2005 Kevin Stewart. As mentioned on the "Submit an Article" page:
If you post to CodeProject then you retain copyright of your article and code. You also give CodeProject permission to use it in a fair manner and also permit other developers to use the sourcecode associated with your articles in their own applications as long as they do not remove your copyright notices or try and take credit for your work.
I would love for you to use my code, in fact I encourage it. I haven't touched this class in awhile as I've been experimenting with Ruby lately. I do have some ideas for a new version. I may do it in Ruby first and follow up with a C# version. Glad you find this class useful!
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
I sure hope it is OK for me to use this in an application I'm working on
I was just adding some comments to the class for the sake of documentation (NDoc rules !) and while trying to explain the behaviours of the Minimum and Maximum properties I ran into this issue:
Assuming that
private const int DefaultMinimum = 6;
private const int DefaultMaximum = 10;
then what if one sets minimum to 12 and then maximum to 10 ? In that case the code
---------------------------------------------------------------
public int Maximum
{
get { return this.maxSize; }
set
{
this.maxSize = value;
if ( this.minSize >= this.maxSize )
{
this.maxSize = PasswordGenerator.DefaultMaximum;
}
}
}
---------------------------------------------------------------
will see that minSize >= maxSize (12 >= 10) and thus set maxSize to defaultMaximum which is 10. Then you have minSize=12 and maxSize=10 - what happens then ?
Anyway, I've added Dirk Vandenheuvel's validate method to my version of the class and thrown in some commens if anybody wants it (I had to turn off HTML tags in this post to preserve the xml comments):
---------------------------------------------------------------
using System;
using System.Security.Cryptography;
using System.Text;
namespace mynamespace
{
/// <summary>
/// The PasswordGenerator class is a general utility class for generating password
/// based on a number of properties. Once one has set these properties, a random
/// password that complys with these can be generated.
/// </summary>
/// <remarks>
/// The PasswordGenerator class is originally created by Kevin Stewart as posted on
/// http://www.codeproject.com/csharp/pwdgen.asp
/// </remarks>
/// <example>
/// <code>
/// // Create new password by using PasswordGenerator class
/// PasswordGenerator generator = new PasswordGenerator();
/// generator.ConsecutiveCharacters = true;
/// generator.Exclusions = "`'~^|{}\\[](),.\";:<>/"; // Allowed special chars are: !@#$%&*-_=+
/// generator.Minimum = 8;
/// generator.Maximum = 8;
/// generator.RepeatCharacters = true;
/// string randomPassword = generator.Generate();
/// </code>
/// </example>
public class PasswordGenerator
{
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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+[]{}\\|;:'\",<.>/?".ToCharArray();
/// <summary>
/// Default constructor
/// </summary>
public PasswordGenerator()
{
this.Minimum = DefaultMinimum;
this.Maximum = DefaultMaximum;
this.ConsecutiveCharacters = false;
this.RepeatCharacters = true;
this.ExcludeSymbols = false;
this.Exclusions = null;
rng = new RNGCryptoServiceProvider();
}
/// <summary>
/// Generates a random number between the specified bounds
/// </summary>
/// <param name="lBound">Lower bound</param>
/// <param name="uBound">Upper bound</param>
/// <returns>The generated random number</returns>
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 - (uint.MaxValue%(uint)(uBound-lBound)));
do
{
rng.GetBytes(rndnum);
urndnum = System.BitConverter.ToUInt32(rndnum,0);
} while (urndnum >= xcludeRndBase);
return (int)(urndnum % (uBound-lBound)) + lBound;
}
/// <summary>
/// Generates a random character from the specified valid range of characters
/// based on a generated random number between the character arrays bounds
/// </summary>
/// <returns>A random character within the allowed range</returns>
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;
}
/// <summary>
/// Generates the random password based on the specified properties
/// </summary>
/// <returns>The random password</returns>
public string Generate()
{
// Pick random length between minimum and maximum
int pwdLength = GetCryptographicRandomNumber(this.Minimum, this.Maximum);
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();
}
}
pwdBuffer.Append(nextCharacter);
lastCharacter = nextCharacter;
}
if ( null != pwdBuffer )
{
return pwdBuffer.ToString();
}
else
{
return String.Empty;
}
}
/// <summary>
/// The class will by default generate passwords with the characters
/// a-z, A-Z, 0-9 and these special characters:
/// `~!@#$%^&*()-_=+[]{}\\|;:'\",<.>/?
/// By specifying an Exclusions string, one can exclude some of these
/// special characters
/// </summary>
public string Exclusions
{
get { return this.exclusionSet; }
set { this.exclusionSet = value; }
}
/// <summary>
/// Defines the minimum length of the generated password
/// </summary>
/// <remarks>
/// Note that the absolute minimum size is 6. Setting a value smaller than
/// 6 will have no effect
/// </remarks>
public int Minimum
{
get { return this.minSize; }
set
{
this.minSize = value;
if ( PasswordGenerator.DefaultMinimum > this.minSize )
{
this.minSize = PasswordGenerator.DefaultMinimum;
}
}
}
/// <summary>
/// Defines the maximum length of the generated password
/// </summary>
/// <remarks>
/// Note that if the maximum size is set to something smaller than
/// <see cref="Minimum"/>, the maximum will be set to 10
/// </remarks>
public int Maximum
{
get { return this.maxSize; }
set
{
this.maxSize = value;
if ( this.minSize >= this.maxSize )
{
this.maxSize = PasswordGenerator.DefaultMaximum;
}
}
}
/// <summary>
/// Defines whether the generated password may contain any special characters
/// at all, or just letters and numbers
/// </summary>
public bool ExcludeSymbols
{
get { return this.hasSymbols; }
set { this.hasSymbols = value;}
}
/// <summary>
/// Defines whether the generated password may contain the same character
/// more than once
/// </summary>
public bool RepeatCharacters
{
get { return this.hasRepeating; }
set { this.hasRepeating = value;}
}
/// <summary>
/// Defines whether the generated password may contain the same character
/// repeated after itself
/// </summary>
public bool ConsecutiveCharacters
{
get { return this.hasConsecutive; }
set { this.hasConsecutive = value;}
}
/// <summary>
/// Validates a password against the defined properties
/// </summary>
/// <remarks>
/// The Validate(...) method is originally posted by Dirk Vandenheuvel as a
/// comment to the original article.
/// </remarks>
/// <param name="password">The password to validate</param>
/// <returns>True if the password is valid, otherwise false</returns>
public bool Validate(string password)
{
int iCount = 0;
if (password.Length < minSize || password.Length > maxSize)
return(false);
// check for Consecutive characters
if (!hasConsecutive) // cannot have consecutive characters
{
for (iCount = 0; iCount < password.Length-1; iCount++)
{
if (password[iCount] == password[iCount+1])
return(false);
}
}
if (!hasRepeating) // cannot have repeating characters
{
for (iCount = 0; iCount < password.Length; iCount++)
{
int index = password.IndexOf(password[iCount]);
while (index != -1)
{
if (index != iCount)
return(false);
index = password.IndexOf(password[iCount]);
}
}
}
if (Exclusions != null) // cannot have characters from exclusion string
{
for (iCount = 0; iCount < password.Length; iCount++)
{
if (Exclusions.IndexOf(password[iCount]) != -1)
return(false);
}
}
if (ExcludeSymbols) // cannot contain 'symbols'
{
for (iCount = UBoundDigit; iCount < pwdCharArray.GetUpperBound(0); iCount++)
{
if (password.IndexOf(pwdCharArray[iCount]) != -1)
return(false);
}
}
return(true);
}
}
}
---------------------------------------------------------------
<span style="font-family:verdana; font-size:10px">Do you know why it's important to make fast decisions? Because you give yourself more time to correct your mistakes, when you find out that you made the wrong one. </span><span style="font-family:verdana; font-size:10px"><i>Chris Meech on deciding whether to go to his daughters graduation or a Neil Young concert</i></span>
|
|
|
|
|
Jan, thank you for adding the comments for NDOC & Kevin thank you for the nice code!
Danny Crowell
www.crowsol.com
|
|
|
|
|
You can treat a string as a character array, which means you don't need to go through the process of dropping it into an array..
instead of...
private char[] pwdCharArray = "abcdefghijklmnopqrstuvwxyzABCDEFG" +
"HIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+[]{}\\|;:'\",<" +
".>/?".ToCharArray();
private string pwdChars = ....; //no .ToCharArray()
and higher up, you can use pwdChars[index] the same as pwdCharArray[index] .. this is just an fyi, and a relatively small notation.. nice piece of code.
--
Michael J. Ryan - tracker1(at)theroughnecks(dot)com - www.theroughnecks.net
icq: 4935386 - AIM/AOL: azTracker1 - Y!: azTracker1 - MSN/Win: (email)
|
|
|
|
|
I believe that if the RepeatCharacters bool is set to false (do not allow repeat chars) and the password length is greater than the length of available chars, then the generate code enters an infinite loop.
A quick fix would be to ignore the RepeatCharacters value and continue reusing those characters after that point, as in the code below: (or just return the results thus far)
if ( false == this.RepeatCharacters )
{
string temp = pwdBuffer.ToString();
int duplicateIndex = temp.IndexOf(nextCharacter);
int upperBound = pwdCharArray.GetUpperBound(0);
if ( true == this.ExcludeSymbols )
{
upperBound = PasswordGenerator.UBoundDigit;
}
if (pwdLength <= upperBound)
{
while ( -1 != duplicateIndex )
{
nextCharacter = GetRandomCharacter();
duplicateIndex = temp.IndexOf(nextCharacter);
}
}
}
Although this takes into account the upperBound of the available chars, it does not include the count of the excluded chars list.
.frihani
|
|
|
|
|
Here's my alternative, shorter version:
public class AlphaNumericPasswordGenerator
{
public string Generate()
{
return MD5Hash(this.secondsSinceEpoch().ToString());
}
private int secondsSinceEpoch()
{
TimeSpan timeSpan = (DateTime.UtcNow - new DateTime(1970, 1, 1));
return (int) timeSpan.TotalSeconds;
}
private string MD5Hash(string Data)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hash = md5.ComputeHash( Encoding.ASCII.GetBytes(Data) );
StringBuilder stringBuilder = new StringBuilder();
foreach( byte b in hash )
{
stringBuilder.AppendFormat("{0:x2}", b);
}
return stringBuilder.ToString();
}
}
www.sloppycode.net
|
|
|
|
|
Nice! Thanks for sharing your approach.
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
Worth noting that mine doesn't work unless you Thread.Sleep(100) and use the random number generator, if you're generating inside a loop!
|
|
|
|
|
Thread.Sleep() for the same amount of time each time will make this predictable after enough generations. If you want to use md5 to get alphanumerics, use input data like so:
rndBytes = new byte[arraySize];<br />
rng = new RNGCryptoServiceProvider();<br />
md5 = new MD5CryptoServiceProvider();<br />
<br />
rng.GetBytes(rndBytes);
byte[] outArray = md5.ComputeHash(rndBytes);<br />
StringBuilder stringBuilder = new StringBuilder();<br />
foreach( byte b in outArray ) {<br />
stringBuilder.AppendFormat("{0:x2}", b);<br />
}<br />
return stringBuilder.ToString();
|
|
|
|
|
public bool Validate(string password)
{
int iCount = 0;
if (password.Length < minSize || password.Length > maxSize)
return(false);
if (!hasConsecutive)
{
for (iCount = 0; iCount < password.Length-1; iCount++)
{
if (password[iCount] == password[iCount+1])
return(false);
}
}
if (!hasRepeating)
{
for (iCount = 0; iCount < password.Length; iCount++)
{
int index = password.IndexOf(password[iCount]);
while (index != -1)
{
if (index != iCount)
return(false);
index = password.IndexOf(password[iCount]);
}
}
}
if (Exclusions != null)
{
for (iCount = 0; iCount < password.Length; iCount++)
{
if (Exclusions.IndexOf(password[iCount]) != -1)
return(false);
}
}
if (ExcludeSymbols)
{
for (iCount = UBoundDigit; iCount < pwdCharArray.GetUpperBound(0); iCount++)
{
if (password.IndexOf(pwdCharArray[iCount]) != -1)
return(false);
}
}
return(true);
}
|
|
|
|
|
Thanks, Dirk! I should've implemented validation in the original code, but I'm a slacker. However, I have been considering a new version where you can specify a regular expression as a way to generate the password. Then, you could use the same input regex to validate the output. I'll post it once I get around to writing it!
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
Is it my imagination...or does GetCryptographicRandomNumber not seem to return an integer between the lbound and ubound!
|
|
|
|
|
nope...it was my imagination after all!
|
|
|
|
|
Hello. I am very new in C programing. i have to do a class project and would really love to include a password requester in it. Where, when someone presses a set of keys, another screen will pop out and request for a password to shut the program down. With out the right pass the pop out will close and return to the original page.
A few things you might want to know.
1)The user cannot use the mouse to shut the program down.
2)I was wondering if i could include the if and else commands on the pop out for the password page.
like
if(password is right)
{
Allow shut down.
}
else
{
pop up closes
}
But was thinking, it won't be case sensitive.
So, i really need all of your expertise. Please... I need it badly. PLease help. I might get lost on this new found site. So if possible, you can reply to me via e-mail at goddime@yahoo.ca
Or else, i would try to find this forum again. thanks alot for your kind help.
Oh yah.. since i am so new, i really hope you can include the command from starting to end. Which includes #include <stdio.h> and ends with
system("pause");
return 0
}
Cos i keep getting confused with the codes on this site. Finally, I need the code in C program. Not other compilers. Teacher's rule. I hope you can include lots of details. So i know why and how the code is working, and created. thanks alot.
|
|
|
|
|
private char[] pwdCharArray = {<br />
'a','b','c','d','e','f','g','h','i','j','k','l','m',<br />
'n','o','p','q','r','s','t','u','v','w','x','y','z',<br />
'A','B','C','D','E','F','G','H','I','J','K','L','M',<br />
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',<br />
'0','1','2','3','4','5','6','7','8','9','`','~','!',<br />
'@','#','$','%','^','&','*','(',')','-','_','=','+',<br />
'[',']','{','}','\\','|',';',':','\'','"',',','<',<br />
'.','>','/','?'<br />
}
can be simplified (for ease of typing, and perhaps also reading) using the string's ToCharArray() method, to:
<br />
private char[] pwdCharArray = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+[]{}\\|;:'\",<.>/?".ToCharArray();<br />
|
|
|
|
|
Good suggestion! Might make it into my next update. Thanks!
Kevin
"Semicolons in a programming language are like mother's milk."
|
|
|
|
|
Interesting article, but there is a not so small gotcha.
A rather large bias is introduced in this line in GetCryptographicRandomNumber()
int number = ( Int32.Parse(rndnum[0].ToString()) % uBound )
The problem is that the modulo operator "%" will produce an uneven distribution, especially where the operand is only a byte (0-255). The bias is variable depending on the value of upperBound and can significantly skew the distributions of characters. If you increase the random number range to 32 bits it won't eliminate the bias but it becomes trivial.
Also this section has a significant bias to return lBound whenever lBound is >0.
if ( lBound > number )
{
number = lBound;
}
-Marty
|
|
|
|
|
Here's a possible hack:
protected int GetCryptographicRandomNumber(int lBound, int uBound)
{
byte[] rndnum = new Byte[4];
rng.GetBytes(rndnum);
uint urndnum = System.BitConverter.ToUInt32(rndnum,0);
return (int)(urndnum % (uBound-lBound)) + lBound;
}
-Marty
|
|
|
|
|