## Friday, December 23, 2011

### I hope you find this blog enjoyable and helpful. Support it with a small donation.

One of the easiest ways to increase your security while browsing the net is to review the quality of your passwords.  It's not difficult, and it doesn't take long.

The reason for having complex passwords is pretty obvious.  If an attacker is trying to break a password by guessing, it's going to take a much longer to guess a password that's 15 characters and has punctuation symbols in it, than guessing an 8 character password with only letters.  This task is done by software and can be done rather quickly in some cases.  There are other reasons for having a complex password relating to how they are stored in hashes.  Short passwords using a small symbol set can be recovered from their hash using pre-compiled rainbow tables.

Now let's say that you have chosen a completely random password that no-one would ever guess and you decide to use it for everything.  If one of the sites that you use this password on were to have poor security and your password was discovered, the attacker has access to all your accounts.  Not a good thing.

Some people have schemes like replacing the letters with other symbols, such as "MY 5E(RET P@55W0RD", these are safer but still not secure.  There is a pretty good chance whatever secret scheme you come up with has been thought of by someone before.  There's some good information on Wikipedia about passwords. en.wikipedia.org/wiki/Password_strength & en.wikipedia.org/wiki/Password are worth a read.

Ideally a password should be as long as possible and made up of randomly selected symbols from an allowed set.  In most cases the allowed set will be made up of a subset of the characters that appear on your keyboard, and randomly selecting them can be a hard task.  For this reason I put together a python script that would generate random passwords for me.  It's a bit hacky but gets the job done.  For a bit of fun I thought I would make it Unicode compatible too.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import struct
import sys
import codecs
import math

#Custom print function to encode output in UTF-8
def UTFprint(in_string):
in_string = in_string.encode('utf-8')
sys.stdout.write(in_string)
sys.stdout.write("\n")
return

#Create command line parser
parser.add_argument('groups', type=str, help='groupcodes l=lower case letters, L=upper case letters, n=numbers, s=space, h=lower case hex, H=upper case hex, g=lower case greek, G=upper case greek, p=punctuation symbols, r=runes, e=high ASCII, k=keyboard symbols, c=CP437')
parser.add_argument('sepspace', type=int, help='number of symbols between separators')
parser.add_argument('-v', '--verbose', default=0, action='store_const', const=1, help='verbose output')
parser.add_argument('-r', '--random', default=0, action='store_const', const=1, help='when selected uses dev/random instead of dev/urandom')
args = parser.parse_args()

#define symbol strings
L_str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' #upper case letters
l_str = 'abcdefghijklmnopqrstuvwxyz' #lower case letters
n_str = '0123456789' #numbers
s_str = ' ' #space
H_str = '0123456789ABCDEF' #upper case hex
h_str = '0123456789abcdef' #lower case hex
g_str = 'αβγδεζηθικλμνξοπρστυφχψω'.decode('utf8') #lower case greek
G_str = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'.decode('utf8') #upper case greek
p_str = '!"#$%\'&()*+,-./;:<=>?@[\]^`_{}|~' #punctuation symbols r_str = 'ᚠᚡᚢᚣᚤᚥᚦᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪᛮᛯᛰ'.decode('utf8') #runes e_str = '☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┛┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ '.decode('utf8') #high ASCII k_str = l_str + L_str + s_str + n_str + p_str #keyboard symbols c_str = e_str + k_str #CP437 #Assemble character list from command line options sym_list = '' if args.groups.count('L') > 0: sym_list = sym_list + L_str if args.groups.count('l') > 0: sym_list = sym_list + l_str if args.groups.count('s') > 0: sym_list = sym_list + s_str if args.groups.count('n') > 0: sym_list = sym_list + n_str if args.groups.count('H') > 0: sym_list = sym_list + H_str if args.groups.count('h') > 0: sym_list = sym_list + h_str if args.groups.count('g') > 0: sym_list = sym_list + g_str if args.groups.count('G') > 0: sym_list = sym_list + G_str if args.groups.count('p') > 0: sym_list = sym_list + p_str if args.groups.count('r') > 0: sym_list = sym_list + r_str if args.groups.count('k') > 0: sym_list = sym_list + k_str if args.groups.count('e') > 0: sym_list = sym_list + e_str if args.groups.count('c') > 0: sym_list = sym_list + c_str #Add extra symbols to the symbol list sym_list = sym_list + args.extras.decode('utf8') #Sort list and remove duplicate symbols sym_list = ''.join(sorted(set(sym_list))) #If the space between separator strings is 0, #set the separator to null separator = args.separate.decode('utf8') if args.sepspace == 0: separator = '' #Set parameter variables num_syms = len(sym_list) pass_length = args.length bits_per_symbol = int(math.ceil(math.log(num_syms,2))) #Declare output variable password = "" #Set loop counters symbols_gathered = 0 separator_count = 0 #/dev/random warning UTFprint("") if args.random == 1: UTFprint("/dev/random has been selected and may take") UTFprint("some time. To decrease the generation time") UTFprint("type some random data in another prompt.") UTFprint("") #Read characters from /dev/urandom and if they are suitable #use them to add symbols to the password if args.random == 1: f = open("/dev/random","rb") else: f = open("/dev/urandom","rb") while (symbols_gathered < pass_length): rnd_str1 = f.read(1) rnd_str2 = f.read(1) rand_int1 = struct.unpack('B', rnd_str1)[0] rand_int2 = struct.unpack('B', rnd_str2)[0] rand_int = rand_int1 * 256 + rand_int2 rand_int = rand_int % pow(2, bits_per_symbol) if (rand_int < num_syms): if (separator_count == args.sepspace): password = password + separator separator_count = 0 password = password + sym_list[rand_int] symbols_gathered = symbols_gathered + 1 separator_count = separator_count + 1 f.close() #Output the results if args.verbose == 1: # if args.random == 1: # UTFprint("/dev/random has been selected and may take") # UTFprint("some time. To decrease the generation time") # UTFprint("type some random data in another prompt.") UTFprint("Symbol Space: " + str(num_syms)) UTFprint("Password Length: " + str(pass_length)) UTFprint("Symbol List: " + "<" + sym_list + ">") UTFprint("Separator String: " + "<" + separator + ">") UTFprint("Password: <" + password + ">") UTFprint("") else: UTFprint(password) Pretty basic. It allows me to do things like use different sets of characters and add separators to the passwords as well. Below are a few basic usage examples.  pass_gen.py examples The syntax is pretty easy: number of characters to generate, symbol sets, extra characters, separator characters, characters between separators, and options -v for verbose and -r for /dev/random instead of /dev/urandom. Example 1 is 16 symbols long from a hexadecimal character set, a colon every 4 symbols, with /dev/random and verbose Example 2 is 16 symbols long using numbers, with tick and cross as extra symbols, a circle separator every 4 symbols, and verbose Example 3 is 16 keyboard symbols with no separators Example 4 is 30 rune symbols with no separators Example 5 is 30 small Greek letters with no separators Here is a link to the file. pass_gen.py With all the quirks of different shells and flavours of linux the unicode stuff might not work too well, most cases it should be a matter of tweaking things. After I wrote the script I saw a simple command on Hak5 that can generate a password. It's functionality covers pretty much any password you would need to create, and is so much simpler. /dev/urandom | tr -dc A-Za-z0-9_ | head -c8 ; echo With a bit of modification I came up with this that generates multiple passwords. cat /dev/urandom | tr -dc '[a-z][A-Z][0-9]-_!@#$%^&*()_+{}|:?=' | fold -w 10| head -n 5

4uJM0FV2Bc
Jx!CA0q3r3
sI@rR0PiC1
SPVJ{+d\$b_
MUWm@&+Uuv

See how easy it is to create strong passwords.  This is of course no guarantee that you wont have one of your accounts compromised in the future, but it's a simple step that will make your account more secure and less attractive to hackers.