Couple of weeks ago, a friend of mine mentioned the following:
During a recent password audit it was found that a blonde was using the following password:
When asked why she had such a long password, she said she was told that it had to be at least 8 characters long and include at least one capital.
If true, then the thinking behind generating such a password looks good alright. Pick your favourite characters/places/things and salt it with a completely unrelated term, and get yourself a decent password. (Sacramento has a Disney Store, so may not be completely unrelated; but still good nonetheless.)
Many of us struggle to trust or rely on a third party software to generate and store our passwords for us. I’m no exception. The problem with a third-party generated password is that it’s meant to defy logic. And without logic, it’s hard to remember and memorize it. So what do we do? We either write it down, or let one of these apps remember it for us. And by doing so, we open up an opportunity for moments of life to grip us the wrong way.
Instead, what if we could write a password generating phrase down that would constitute some logic to us individually, without compromising our personal security?
It’s quite doable, if you think about it. One way to think of safe passwords is to use a standard cipher, salted to taste. Take ROT13 for example.1 You can write your favorite phrase down — like the blonde, and then encode it with a cipher like ROT13 whenever using it. Doing so, your password gets harder by an order of magnitude. To take it a few notches up, you could write your own non-standard cipher substitution, and use it. And further up that by yet another order of magnitude, by substituting certain numerals and special characters with other numerals and special characters.2
Here’s one I wrote just for the demo.3 Please do read the comments in the code. They’re self-explanatory.
#!/usr/bin/env python # -*- coding: UTF-8 -*- """ Make your own cipher and use it to generate your custom password. 1. Think of a phrase that you love. 2. Encode it with your custom cipher. 3. Use it as your password. Should you decide to use your own cipher, then think of a suitable set of characters to substitute. The following is just an example. """ from sys import argv import string """ # Your custom cipher `user` is standard character set. `subs` is character substitution set for `user`. """ user = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" # Start editing. # Remember to use your own custom substitution below. subs = "fghijvwxyzabcdekVWXYZAmnopqrstuBCDEKLMNOPQRSTUlFGHIJ" # End of editing. def main(): print "Remember to salt your familiar phrase." try: usertxt = argv except IndexError: usertxt = raw_input("Text to be encoded: ") ciptrans = string.maketrans(user, subs) p = usertxt.translate(ciptrans) print "Plain text : ", usertxt print "Ciphered text: ", p pass if __name__ == '__main__': main()
When the script is run, this is what you’d see.
$ python mycip.py Text to be encoded: MickeyminnyGoofyDonaldSacramento~ Plain text : MickeyminnyGoofyDonaldSacramento~ Ciphered text: cEsLuINEOOIwPPBIiPOqMtXqsSqNuOUP~
The code4 is basically just five lines when you strip comments, print statements and def statements away. Here’s how they read:
- Line 1:
useris a defined string of modern alphabets. First in caps, then in lower case.
- Line 2:
subsis the cipher (A simple arrangement of characters I choose to substitute for every character in the string assigned
user). For every capital
A, I substitute it with lower case
g, and so on. The cipher is intentionally a random arrangement of alphabets, and in no particular order to thwart a cracker if he gets thus far. (In this demo, I simply took the first list, mixed and mashed it randomly to come up with the string called
- Line 3:
usertxttakes in keyboard input — enter the phrase you want to encode with your custom cipher as defined above.
- Line 4:
ciptranstells python to define the translate method of
subsstring, alphabet by alphabet.
- Line 5:
ptranslates (encodes or substitutes) the text entered at the keyboard with alphabets in
That’s it; and once you start using it, you’ll notice that while this python script may be a convenience for generating your custom password, it’s really your cipher that’s important, i.e., the
subs list, that you don’t ever want to lose. Print and tape one to your refrigerator, and the other to your bathroom mirror. :-)
Update (Aug 25, 2012): Six months after I wrote this post, Mr. Monroe published his comic, Password Strength, and then last week, Mr. Honan, said this following while recovering from a targeted attack that wiped his system clean:
I hit an immediate problem: I didn’t know any of my passwords…I’m a heavy 1Password user. I use it for everything. That means most of my passwords are long, alphanumeric strings of gibberish with random symbols. It’s on my iPhone, iPad and Macbook. It syncs up across all those devices because I store the keychain in the cloud on Dropbox…But I didn’t have it on any of our other systems. So now I couldn’t get to my keychain. And so I was stuck in a catch-22. My Dropbox password was itself a 1password-generated litany of nonsense. Without access to Dropbox, I couldn’t get my keychain. Without my keychain, I couldn’t get into Dropbox.
Update: I’ve added argument support to the script above, which means if you provide a phrase while running the script, then it won’t prompt you for the Text to be encoded. Instead, it ciphers the first argument you provide at prompt, e.g., see below:
$ python mycip.py MickeyminnyGoofyDonaldSacramento~ Plain text : MickeyminnyGoofyDonaldSacramento~ Ciphered text: cEsLuINEOOIwPPBIiPOqMtXqsSqNuOUP~
If you have TextExpander, this can be further automated by creating a shell script like the following (using the argument variable inline), and assign the snippet a trigger like
#!/usr/bin/env sh python ~/mycip.py MickeySacramento~ | tr -d '\n' | pbcopy
;pass anywhere, and your password parses your phrase with your custom cipher and produces your ciphered pass to clipboard memory on the fly.
tr -d '\n' removes the carriage return part from your pass produced from python. (Common sense recommends exercising necessary caution when saving your phrases this way.)
It has a simple character substitution, rotated every 13 characters; hence the name. ↩
The custom cipher in the script does not substitute numerals or special characters, but you get the idea, to define it, should you want to. ↩
I wrote the script for python 2.6.1, the one that’s currently on a Mac. For version 3.x, you may have to do the necessary semantic change in the code. (But you’d know that already by looking at the code.) ↩
I know the code is sloppy, and has bad naming convention, but I hope to be excused for being a hobbyist. =) ↩
Popularized by the infamous German ENIGMA machine that used polyalphabetic cipher during WWII to encode messages. That the Germans changed the underlying cipher every 24hours is what really made it impossible to crack in theory, which eventually was brute-forced in part by consistent social engineering from multiple sources to map known letters and words. ↩