Saturday, December 15, 2012

Guids for passwords?

This suggests that repurposing a Guid is a great way to craft a random password of strictly alphanumeric characters. Well, I tested the theory today and am pleased with what came to be. The code in black below could have just been left out, but I kept it for readability.

using System;
using System.Collections.Generic;
using System.Linq;
namespace EQL.Members
{
   public static class PasswordGenerator
   {
      public static string Generate(int lengthOfPassword)
      {
         Guid guid = Guid.NewGuid();
         string secret = guid.ToString().Replace("-", "");
         if (lengthOfPassword > 1 && lengthOfPassword < 32) secret = secret.Substring(0,
               lengthOfPassword);
         return RandomizeTheCaseOnLetters(secret);
      }
      
      private static string RandomizeTheCaseOnLetters(string secret)
      {
         char[] characterArray = secret.ToCharArray();
         char[] arrayForRandomizing = Guid.NewGuid().ToString().Replace("-",
               "").ToCharArray();
         List<bool> listForRandomizing = arrayForRandomizing.Select(c => ((int) c%2 == 0)
               
? true : false).ToList();
         int counter = 0;
         bool containsNumber = false;
         bool containsLetter = false;
         while (counter < characterArray.Length)
         {
            char character = characterArray[counter];
            int characterEncoding =
(int)character;
            if (characterEncoding > 49)
            {
               containsLetter = true;
               string stringifiedCharacter = character.ToString();
               if (listForRandomizing[counter])
               {
                  stringifiedCharacter = stringifiedCharacter.ToUpper();
               } else {
                  stringifiedCharacter = stringifiedCharacter.ToLower();
               }
               characterArray[counter] = stringifiedCharacter.ToCharArray()[0];
            } else {
               containsNumber = true;
            }
            counter++;
         }
         characterArray = EnsurePresenceOfBothOneDigitAndOneLetter(characterArray,
               containsNumber, containsLetter);
         return characterArray.Aggregate("", (current, c) => current + c.ToString());
      }
      
      private static char[] EnsurePresenceOfBothOneDigitAndOneLetter(char[]
            characterArray, bool containsNumber, bool containsLetter)
      {
         if (!containsNumber)
         {
            characterArray[0] = '0';
         }
         if (!containsLetter)
         {
            characterArray[0] = 'a';
         }
         return characterArray;
      }
   }
}

 
 

My tests:

using System.Text.RegularExpressions;
using EQL.Members;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace EQL.Tests
{
   [TestClass]
   public class PasswordGeneratorTests
   {
      [TestMethod]
      public void GuidToAlphanumericPasswordConversionBehavesAsExpected()
      {
         string password = PasswordGenerator.Generate(31);
         Assert.AreEqual(password.Length, 31);
         Assert.IsTrue(Regex.IsMatch(password, @"^[A-Za-z0-9]+$"));
      }
      
      [TestMethod]
      public void PasswordsAlwaysHaveAtLeastOneNumberAndAtLeastOneLetter()
      {
         string password = PasswordGenerator.Generate(2);
         char[] characterArray = password.ToCharArray();
         int counter = 0;
         bool containsNumber = false;
         bool containsLetter = false;
         while (counter < characterArray.Length)
         {
            char character = characterArray[counter];
            int characterEncoding =
(int)character;
            if (characterEncoding > 49)
            {
               containsLetter = true;
            } else {
               containsNumber = true;
            }
            counter++;
         }
         Assert.IsTrue(containsNumber);
         Assert.IsTrue(containsLetter);
      }
   }
}

No comments:

Post a Comment