Last active
December 30, 2015 10:19
-
-
Save erinaceous/7815007 to your computer and use it in GitHub Desktop.
Tiny guide for getting workable Aber passwords
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Password generator for Aber Uni users | |
Owain Jones [github.com/doomcat] | |
IS's systems are very picky about the passwords they let you use. It | |
can prove to be very difficult to come up with a password that's both | |
memorable and secure for it. | |
What I had started doing is generating passwords which are accepted | |
by IS, but hard to remember. However, they were easy to reproduce, | |
if you knew the original word it was based on and the method used to | |
create it -- essentially generating a hash of a string of memorable | |
text. Except not using anything common like MD5 or SHA hashing. | |
I've since extended that to create passwords like this that are also | |
fairly memorable after seeing them a few times, using the "rule of | |
threes" -- it's easier to remember passwords if you can chunk them up | |
into sets of three characters, as you can give them a rhythm then. | |
Same thing we do with phone numbers, postcodes and license plates. | |
So, what this script does: | |
- Takes a normal, short string. | |
- Creates a hash of it that is guaranteed to be a multiple of | |
three in length. | |
- Splits that hash up into sets of three | |
- Uppercases and lowercases the sets at random: | |
abc DEF GHI jkl | |
YMMV when it comes to remembering groups of three things, maybe it's | |
just me it works for. Maybe you're weird and you remember things in | |
groups of four best. So I've made that changeable. | |
""" | |
from __future__ import print_function | |
import hashlib | |
SET_LENGTH = 3 # default length of the character sets | |
NUM_CHUNKS = 4 | |
UPPERCASED = [0, 1, 0, 1] | |
SEPARATOR = ' ' | |
def hashing_method(string): | |
"""However you want to hash things. | |
Arguments: | |
string: Plaintext string | |
Returns: Hash of original string. | |
""" | |
return hashlib.sha1(str(string).encode("utf-8")).hexdigest().lower() | |
def do_the_thing(password, set_length=SET_LENGTH, chunks=NUM_CHUNKS, | |
uppercase_chunks=UPPERCASED, separator=SEPARATOR, | |
hashing_method=hashing_method): | |
"""Do everything mentioned in this module's docstring. | |
Arguments: | |
password: The plaintext password you want to create a better | |
password from. | |
set_length: The length of each chunk of the password. Defaults to | |
SET_LENGTH. | |
chunks: Number of chunks to use for your password. | |
Default: NUM_CHUNKS. | |
uppercase_chunks: Which of the chunks to make uppercase. Default: | |
UPPERCASED | |
separator: The separator to use between chunks. Default: SEPARATOR | |
hashing_method: The method used to generate a hash from the | |
original password. Defaults to this module's | |
"hashing_method()" function. Can be any function | |
that takes and returns a single string. | |
Returns: (Hopefully) a password that IS will actually accept :) | |
""" | |
pw_hashed = hashing_method(password) | |
chunks = [pw_hashed[x:(x + set_length)] for x in range(0, chunks)] | |
for i, x in enumerate(uppercase_chunks): | |
if x == 1: | |
chunks[i] = chunks[i].upper() | |
return separator.join(chunks) | |
if __name__ == '__main__': | |
import argparse | |
parser = argparse.ArgumentParser( | |
description=__doc__, | |
formatter_class=argparse.RawDescriptionHelpFormatter | |
) | |
parser.add_argument( | |
"password", | |
help="The (plaintext) password you want to base your password on") | |
parser.add_argument( | |
"-l", "--section-length", type=int, default=SET_LENGTH, | |
help="The length of each memorable chunk of password (Default: %d)" % | |
SET_LENGTH) | |
args = parser.parse_args() | |
print(do_the_thing(args.password)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta content="text/html; charset=windows-1252" http-equiv="content-type"> | |
<title>Generating passwords for Aber Uni accounts</title> | |
</head> | |
<body> | |
<h1>Generating Passwords that Aber Uni's Password System will Actually | |
Accept</h1> | |
<p>So anyone who's had to fight the mandatory once-per-year password | |
changing system knows that it is the most fussy thing in the world. The | |
rules seem to be:</p> | |
<ul> | |
<li>No words (in any language)</li> | |
<li>No random letters</li> | |
<li>No ASCII characters</li> | |
<li>No glyphs that human beings could possibly comprehend</li> | |
</ul> | |
And it can be pretty difficult to create a password that is memorable yet | |
cryptic enough for the password system to be satisfied with.<br> | |
<br> | |
I've developed my own little system for generating passwords. Instead of | |
generating passwords I can <em>directly remember</em>, I generate passwords | |
which I can <strong>remember how I generated</strong>.<br> | |
For example (demonstrated with a bit of Python code):<br> | |
<ol> | |
<li>Take a plaintext passphrase, one you will easily remember. For the | |
purposes of this, I chose <code>butts</code>.</li> | |
<li>Generate a hash of the phrase. I chose to use an MD5 hash -- I'm only | |
using the first part of the hash<span style="font-family: monospace;">:<br> | |
<code>import hashlib<br> | |
pw_hashed = hashlib.sha1("butts".encode("utf-8")).hexdigest()</code></span><br> | |
The hash I got was <code>cd89a20adde7a608f3331e71c37bdfa087bacbf3</code></li> | |
<li>Divide the hash into fixed-length chunks. I chose to use four chunks | |
of three characters, because I find things in sets of three easier to | |
remember.<br> | |
<code>chunks = [pw_hashed[x:x+3] for x in range(0, 4)]</code><br> | |
The resulting list: <code>['cd8', 'd89', '89a', '9a2']</code></li> | |
<li>Next, I make some of the chunks uppercase in a pattern I'm going to | |
remember:<br> | |
<code>pattern = [0, 1, 0, 1]<br> | |
for i, x in enumerate(pattern):<br> | |
if x == 1:<br> | |
chunks[i] = | |
chunks[i].upper()</code><br> | |
(So now <code>chunks</code> looks like this: <code>['cd8', 'D89', | |
'89a', '9A2']</code>)</li> | |
<li> Finally, I join the chunks back together into a string, with | |
something separating the chunks. In this example, I'm just using spaces, | |
you could use dots or dashes or whatever though:<br> | |
<code>print(' '.join(chunks))</code></li> | |
<li>Which gets me my password; <code>cd8 D89 89a 9A2</code></li> | |
</ol> | |
<p>This is just an example; the hashing or the dividing into chunks and | |
stuff isn't set in stone. The point is to remember how to <strong>programatically | |
recreate </strong>a password by remembering <strong>how you coded it</strong> | |
rather than trying to memorize a string of random characters straight | |
away. That way you don't have to have it lying around anywhere, and you | |
don't need to keep the plaintext original passphrase you chose written | |
down either because it'll be something you can remember super easy :) It | |
should be safe to keep scripts to (re)generate passwords lying around as | |
long as you don't store your original passphrase in it (so pass it in as | |
an argument to the code).</p> | |
<p>I turned the example Python code on this page into a working script. It's | |
<a href="actual_aber_password.py">part of this gist</a>. Feel free to | |
<a href="https://gist.github.com/doomcat/7815007">fork this</a> | |
and point out any flaws or ways to make this better | |
(more memorable password hashes, etc.)</p> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment