diff --git a/twik/twik.py b/twik/twik.py index f147bfd..ff364db 100644 --- a/twik/twik.py +++ b/twik/twik.py @@ -29,80 +29,87 @@ from util import Util import hmac import getpass import argparse - -def enum(**enums): - return type('Enum', (), enums) - -def injectcharacter(mhash, offset, reserved, seed, length, cstart, cnum): - pos0 = seed % length - pos = (pos0 + offset) % length - for i in range(0, length - reserved): - tmp = (pos0 + reserved + i) % length - char = ord(mhash[tmp]) - if char >= ord(cstart) and char < ord(cstart) + cnum: - return mhash - head = mhash[:pos] if pos > 0 else "" - inject = ((seed + ord(mhash[pos])) % cnum) + ord(cstart) - tail = mhash[pos+1:] if (pos + 1 < len(mhash)) else mhash - return head + chr(inject) + tail +import sys -def removespecialcharacters(mhash, seed, length): - inputchars = list(mhash) - pivot = 0 - for i in range(0, length): - if not inputchars[i].isdigit() and not inputchars[i].isalpha(): - inputchars[i] = chr(((seed + pivot) % 26 + ord('A'))) - pivot = i + 1 - return "".join(inputchars) - -def converttodigits(mhash, seed, length): - inputchars = list(mhash) - pivot = 0 - for i in range(0, length): - if not inputchars[i].isdigit(): - inputchars[i] = chr(((seed + ord(inputchars[pivot])) % 10 + - ord('0'))) - pivot = i + 1 - return "".join(inputchars) - -def generatehash(tag, key, length, password_type): - digest = hmac.new(key, tag, sha1).digest() - mhash = digest.encode('base64')[:-2] - - seed = 0 - for i in range(0, len(mhash)): - seed += ord(mhash[i]) - - if password_type == PASSWORDTYPE.NUMERIC: - mhash = converttodigits(mhash, seed, length) - else: - mhash = injectcharacter(mhash, 0, 4, seed, length, '0', 10) - if password_type == PASSWORDTYPE.ALPHANUMERIC_AND_SPECIAL_CHARS: - mhash = injectcharacter(mhash, 1, 4, seed, length, '!', 15) - mhash = injectcharacter(mhash, 2, 4, seed, length, 'A', 26) - mhash = injectcharacter(mhash, 3, 4, seed, length, 'a', 26) - - if password_type == PASSWORDTYPE.ALPHANUMERIC: - mhash = removespecialcharacters(mhash, seed, length) - - return mhash[:length] +class Twik(object): + def injectcharacter(self, mhash, offset, reserved, seed, length, cstart, cnum): + pos0 = seed % length + pos = (pos0 + offset) % length + for i in range(0, length - reserved): + tmp = (pos0 + reserved + i) % length + char = ord(mhash[tmp]) + if char >= ord(cstart) and char < ord(cstart) + cnum: + return mhash + head = mhash[:pos] if pos > 0 else "" + inject = ((seed + ord(mhash[pos])) % cnum) + ord(cstart) + tail = mhash[pos+1:] if (pos + 1 < len(mhash)) else mhash + return head + chr(inject) + tail -def getpassword(tag, private_key, master_key, length, password_type): - mhash = generatehash(private_key, tag, 24, 1) - password = generatehash(mhash, master_key, length, password_type) - print "Your password is %s" % password + def removespecialcharacters(self, mhash, seed, length): + inputchars = list(mhash) + pivot = 0 + for i in range(0, length): + if not inputchars[i].isdigit() and not inputchars[i].isalpha(): + inputchars[i] = chr(((seed + pivot) % 26 + ord('A'))) + pivot = i + 1 + return "".join(inputchars) + + def converttodigits(self, mhash, seed, length): + inputchars = list(mhash) + pivot = 0 + for i in range(0, length): + if not inputchars[i].isdigit(): + inputchars[i] = chr(((seed + ord(inputchars[pivot])) % 10 + + ord('0'))) + pivot = i + 1 + return "".join(inputchars) + + def generatehash(self, tag, key, length, password_type): + digest = hmac.new(key, tag, sha1).digest() + mhash = digest.encode('base64')[:-2] + + seed = 0 + for i in range(0, len(mhash)): + seed += ord(mhash[i]) + + """NUMERIC""" + if password_type == 3: + mhash = self.converttodigits(mhash, seed, length) + else: + mhash = self.injectcharacter(mhash, 0, 4, seed, length, '0', 10) + """ALPHANUMERIC_AND_SPECIAL_CHARS""" + if password_type == 1: + mhash = self.injectcharacter(mhash, 1, 4, seed, length, '!', 15) + mhash = self.injectcharacter(mhash, 2, 4, seed, length, 'A', 26) + mhash = self.injectcharacter(mhash, 3, 4, seed, length, 'a', 26) + + """ALPHANUMERIC""" + if password_type == 2: + mhash = self.removespecialcharacters(mhash, seed, length) + + return mhash[:length] + + + def getpassword(self, tag, private_key, master_key, length, password_type): + if length > 26 or length < 4: + return None + mhash = self.generatehash(private_key, tag, 24, 1) + password = self.generatehash(mhash, master_key, length, password_type) + return password def main(): - global PASSWORDTYPE - PASSWORDTYPE = enum(ALPHANUMERIC_AND_SPECIAL_CHARS=1, ALPHANUMERIC=2, - NUMERIC=3) + """ + ALPHANUMERIC_AND_SPECIAL_CHARS=1 + ALPHANUMERIC=2 + NUMERIC=3 + """ parser = argparse.ArgumentParser() parser.add_argument("tag", type=str, help="generate password for a specified tag") parser.add_argument("-c", "--chars", type=int, default=-1, - help="length of generated password. Default: 12") + help="length of generated password [4-26]. Default: 12") parser.add_argument("-p", "--profile", type=str, default='Profile', help="profile to use. Default:'Profile'") parser.add_argument("-t", "--passwordtype", type=int, choices=[1, 2, 3], @@ -115,13 +122,20 @@ def main(): ''') args = parser.parse_args() + if args.chars > 26 or args.chars < 4: + print "Invalid password length [4-26]" + sys.exit(2) + util = Util(args.tag, args.chars, args.passwordtype, args.profile) master_key = getpass.getpass(prompt='Master Key: ') - getpassword(args.tag, util.get_privatekey(), master_key, + twik = Twik() + password = twik.getpassword(args.tag, util.get_privatekey(), master_key, util.get_chars(), util.get_passord_type()) + print "Your password is %s" % password + if __name__ == "__main__": main()