What is Diceware?
Diceware™ is a method for picking passphrases that uses ordinary dice to select words at random from a special list called the Diceware Word List. Each word in the list is preceded by a five digit number. All the digits are between one and six, allowing you to use the outcomes of five dice rolls to select a word from the list.1
Here’s what a Diceware word list looks like:
1
2
3
4
5
6
7
8
9
10
11
12
...
16655 clause
16656 claw
16661 clay
16662 clean
16663 clear
16664 cleat
16665 cleft
16666 clerk
21111 cliche
21112 click
...
The complete list contains 7776 unique words. I’ve posted the one I use on my GitHub. You can download it here.
Breaking it down
Objective: Create a secure password
- Roll a die five times to create a five digit number (eg. 52334)
- Get a special char and a number
- Correlate roll to a word in the word list
- Profit
Code
1
import random, string
As you can see, the only libraries you’ll need to import are random
and string
. Random for the simulated die rolls and string so we don’t have to type out all the special characters.
Main function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def generate_password():
passwd = []
num = 3
# Generate a random number between 1 and 999
rand_num = str(random.randint(1, 999))
for w in range(num):
# Generate 5 random numbers between 1 and 6
roll = ''.join([str(random.randint(1, 6)) for _ in range(5)])
word = wl_dict[roll]
# Randomly capitalizes the current word
if random.randrange(2) == 1:
word = word.capitalize()
# Appends word to array
passwd.append(word)
# Generate a random special character
passwd.append(random.choice(string.punctuation))
# Concatenate the words, number, and special character to form the password
final_pw = ''.join(passwd) + rand_num
return final_pw
The num
variable allows us to specify how many words we want in our password. For me, three is the sweet spot. Next we generate a random number between 1-999. Finally, we get to our beefy for loop.
roll
: simulates our die roll resulting in a five digit numberword
: searches our dictionary and stores the word in our variable
The if statement basically does a coin flip and will capitalize the word if it rolls a one. The two lines below the if statement append the selected word and a random special character to our empty passwd
array. At the end our passwd
variable will look like [‘Junkie’, ‘~’, ‘undivided’, ‘%’, ‘Disorder’, ‘#’]
final_pw
: joins all of the elements in thepasswd
array into one string and adds our random number (ie. “Junkie~undivided%Disorder#943”)
Creating our word list dictionary
1
2
3
4
5
6
7
8
# Load the diceware word list
with open("diceware.txt", "r") as f:
wl = [line.strip() for line in f]
wl_dict = {}
for line in range(len(wl)):
l = wl[line].split("\t")
wl_dict[l[0]] = l[1]
This part used to be way longer and over complicated for no reason. But, I fixed it. While our file is open we create the array wl
which contains every line. However, our file has tabs in it for some reason so we can’t just split it normally. Instead we’ll create an empty dictionary and a for loop. In our for loop we can iterate line by line and split by that tab with \t
. Then we just append to our dictionary wl_dict
with the key being the number l[0]
and value being the word l[1]
.
Calling our function
1
print("Password = " + generate_password())
Finally, we call our function which returns our finished password and print.
Conclusion
If you made it this far, you now have to go and change all your passwords. I hope you’re not reusing the same password for everything. Tisk Tisk Tisk. If you want a video tutorial, the YouTube channel Computerphile2 has a great video going over this topic. If you just want to run the script and not have to worry about all the coding, download it from my GitHub3 or run the web app I spent way too long on above.