IEnumerable<char> Random Password Generator

Last time I showed that IEnumerable uses lazy evaluation with a Fibonacci Sequence generator as an example. Perhaps a more practical example of an infinite series is a random character sequence from which you could generate passwords. This is using IEnumerable a lot like the /dev/random file in Unix.

This example is a password generator program based on a RandomCharSequence type which implements IEnumerable<char>. RandomCharSequence is again not much more than a factory for RandomCharEnumerator. The interesting thing here is that it passes the set of characters to be used in the random generation to RandomCharEnumerator. The character sets are upper, lower, digit and special and are themselves statically defined but are composable  using a CharTypes enumeration.

Like FibonacciSequence, RandomCharSequence is an infinite set. You have to limit how much of it you grab at a particular time using the Take(int) extension method from System.Linq.

RandomCharSequence as Password Generator

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Security.Cryptography;
using System.Reflection;
using System.Collections.ObjectModel;

namespace NewPassword
{
    class Program
    {
        static void Main( string[] args )
        {
            int length = -1;
            int count  = -1;
            if( args.Length > 0 )
            { int.TryParse( args[0], out length ); }
            else
            { length = 8; }
            if( args.Length > 1 )
            { int.TryParse( args[1], out count ); }
            else
            { count = 5; }
            
            var pwdseq = new RandomCharSequence();
            for( int i = 0; i < count; i++ )
            {
                Console.WriteLine( pwdseq.Take( length ).ToArray() );
            }
        }
    }

    [Flags]
    public enum CharTypes
    {
        Lower   = 0x01,
        Upper   = 0x02,
        Digit   = 0x04,
        Special = 0x08,
        All     = Upper | Lower | Digit | Special
    }
    public class RandomCharSequence : IEnumerable<char>
    {
        static readonly IEnumerable<char> s_lower   = new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'q', 'y', 'z' };
        static readonly IEnumerable<char> s_upper   = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Q', 'Y', 'Z' };
        static readonly IEnumerable<char> s_digit   = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
        static readonly IEnumerable<char> s_special = new[] { '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~' };

        //these static properties must exactly match the flags defined in the CharTypes enum
        private static IEnumerable<Char> Lower   { get{ return s_lower; } }
        private static IEnumerable<Char> Upper   { get{ return s_upper; } }
        private static IEnumerable<Char> Digit   { get{ return s_digit; } }
        private static IEnumerable<Char> Special { get{ return s_special; } }

        public RandomCharSequence() : this( CharTypes.All ){}
        public RandomCharSequence( CharTypes charTypes )
        {
            CharTypes = charTypes;
        }

        public CharTypes CharTypes {get; set;}

        public IEnumerator<char> GetEnumerator()
        {
            List<char> pool = new List<char>();
            foreach( var type in (CharTypes[])Enum.GetValues(typeof(CharTypes) ) )
            {
                //CharTypes.All is not a single bit flag. We don't want that one.
                if( type != CharTypes.All && (CharTypes & type) == type )
                {
                    //use reflection to add the static char list properties which
                    //match the flag bits.
                    pool.AddRange( 
                        (IEnumerable<char>)typeof(RandomCharSequence).GetProperty( 
                            type.ToString(), 
                            BindingFlags.Static | BindingFlags.NonPublic 
                            ).GetValue( this, null )
                        );
                }
            }
            return new RandomCharEnumerator( pool );
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public class RandomCharEnumerator : IEnumerator<char>
    {
        public RandomCharEnumerator( IList<char> pool )
        {
            Disposing = false;
            Pool      = new ReadOnlyCollection<char>( pool );
            Random    = RandomNumberGenerator.Create();
        }

        RandomNumberGenerator Random { get; set; } 
        public IList<char> Pool { get; private set; }
        int Index { get; set; }

        public char  Current
        {
            get { return Pool[Index]; }
        }
        object IEnumerator.Current { get { return Current; } }


        private bool Disposing{ get; set; }
        public void  Dispose()
        {
            //RandomNubmerGenerator only implements IDisposable as of .NET Framework 4.0
            IDisposable randDisposable = Random as IDisposable;
            if( randDisposable != null && !Disposing )
            {
                randDisposable.Dispose();
                Disposing = true;
            }
        }

        public bool  MoveNext()
        {
            Index = Random.GetInt( 0, Pool.Count );
            //infinite sequence of random chars. There's always a next one.
            return true;
        }

        public void  Reset(){ /* nothing */ }
    }

    public static class RandomNumberGeneratorExtension
    {
        public static int GetInt( this RandomNumberGenerator random, int min, int max )
        {
            if( min >= max )
                throw new InvalidOperationException( "The min value must be less than the max value." );
            byte[] buff = new byte[8];
            random.GetBytes(buff);
            long r = Math.Abs( BitConverter.ToInt64( buff, 0 ) );
            return (int)((long)min + (r % ((long)max - (long)min)));
        }
    }
}

Compile and run the program to pull some password strings out of the infinite random character sequence.

PS> csc -nologo -out:newpassword.exe ./Program.cs; ./newpassword 10 15
^mVhNjHdds
o4Eq=q;`es
%1R\rL3r3{
+PFRrl4e)u
TvAB+tjNu-
?8zCq~{?KB
@WY)+sF;^I
B+)'?sRee-
G'\e)QkjYp
L8(`@o};$$
)j`$7?RG)4
QcC{4;fZcb
_S89_tm]76
}kAiirj^!=
,qq|%-(s)@

Update: RandomNumberGenerator does not implement IDisposable until .Net Framework 4.0 so I needed to dynamically invoke the interface if present rather than statically compiling with Random.Dispose() in there.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: