Monthly Archives: March 2016

Generating Diceware Passphrases with Powershell

Diceware is a method to create a passphrase by rolling dice to select random words from a word list. Diceware passphrases are easy to remember, but hard to crack. Micah Lee has a good article here that explains all the details about what they are and how to use them. The Diceware home page has more technical details on how the system works and has several word lists available for download. The basic idea is that you roll 5 dice to get a 5 digit number and then look that number up in the word list to select each word. Repeat until your passphrase has as many words as you want.

To truly get the benefit of a Diceware passphrase, you need to roll physical dice to get true randomness. However, spend a little time with Google and you will see that there are many computer implementations that generate Diceware passphrases. I decided to write one in Powershell.

The first thing I wanted to do was to come up with a better random number generator than Get-Random. See my blog post here for a discussion on how I came up with Get-RandomInt.

Once I had a decent random number generator, the biggest question I had was on how to store the word list. I decided to use a Powershell hash table. A Powershell hash table is similar to an array, but consists of multiple key-value pairs. Rather than looking up a value by indexing on the element number like you would in an array, you look up values in a has table by indexing on the key. So $hash[$key] will return the value associated with $key. I set up the word list with the words as values and the dice rolls as keys. So it is very easy to look up a word like this: $word = $wordlist[$roll].

I added another feature. Because the words in the word list vary in length from 1 to 6 characters, it is possible that, even with a 7 or 8 word passphrase (which should be very secure), the passphrase generated could be as short as 7 or 8 characters. To prevent this problem, I provided an option to specify a minimum length for the passphrase.

function New-DicewarePassword {
[CmdletBinding()]
[OutputType([String])]
Param (
   # Word list to use
   [Parameter(Position = 0)]
   [ValidateNotNullOrEmpty()]
   [String]$WordList = '.\diceware.wordlist.asc',

   # number of words in the passphrase
   [ValidateRange(3,999)]
   [int]$NumWords = 5,

   # minimum length of the passphrase to generate
   [Int]$MinLength = 15
)

   #read the words file into a hashtable
   if (Test-Path $WordList) {
      $WordsList = @{}
      Get-Content $WordList |
      Where-Object -FilterScript {
         $_ -match '^\d.*\s.*'
      } |
      ForEach-Object -Process {
         $key, $value = -split $_
         $WordsList[$key] = $value
      }
   } else {
      Write-Warning -Message "File $WordList not found"
     Break
   }
   #initialize other variables
   $NumDice = 5 #Diceware word list is based on rolling 5 dice

   #main loop starts here
   Do {
      $PassPhrase = '' #start with a new passphrase each attempt
      for ($Words = 1;$Words -le $NumWords; $Words++) {
         $RollResult = ''
         for ($RollNum = 1;$RollNum -le $NumDice; $RollNum++) {
            $RollResult = $RollResult += [string](Get-RandomInt -min 1 -max 6)
         }
         $PassPhrase += $WordsList[$RollResult]+' '
      }
   } Until ($PassPhrase.trim().Length -ge $MinLength)
   $PassPhrase, '(Length: {0} chars)' -f $PassPhrase.trim().Length
}