Custom cipher

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."

        usertxt = argv[1]
    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

if __name__ == '__main__':

When the script is run, this is what you’d see.

$ python
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:

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 user and 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 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 ;pass:

#!/usr/bin/env sh
python ~/ MickeySacramento~ | tr -d '\n' | pbcopy

Hit ;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.)

  1. It has a simple character substitution, rotated every 13 characters; hence the name. 

  2. 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. 

  3. 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.) 

  4. I know the code is sloppy, and has bad naming convention, but I hope to be excused for being a hobbyist. =) 

  5. 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.