diff --git a/psudohash.py b/psudohash.py new file mode 100644 index 0000000..f364e2f --- /dev/null +++ b/psudohash.py @@ -0,0 +1,396 @@ +#!/bin/python3 +# +# Created by Panagiotis Chartas (t3l3machus) +# https://github.com/t3l3machus + + +import argparse, sys, itertools + +# -------------- Arguments & Usage -------------- # +parser = argparse.ArgumentParser() + +parser.add_argument("-w", "--word", action="store", help = "Main word to transform", required = True) +parser.add_argument("-sn", "--serial-numbering", action="store", help = "Add comma seperated values to common paddings (must be used with -cp OR -cpb OR -cpa)") +parser.add_argument("-y", "--years", action="store", help = "Comma seperated OR range of year values (e.g., 1990,2022 OR 1990-2000)") +parser.add_argument("-ap", "--append-padding", action="store", help = "Add comma seperated values to common paddings (must be used with -cp OR -cpb OR -cpa)") +parser.add_argument("-cpb", "--common-paddings-before", action="store_true", help = "Add common paddings before each mutated word") +parser.add_argument("-cpa", "--common-paddings-after", action="store_true", help = "Add common paddings after each mutated word") +parser.add_argument("-cpo", "--custom-paddings-only", action="store_true", help = "Use only user provided paddings for word mutations (must be used with -ap AND (-cp OR -cpb OR -cpa))") +parser.add_argument("-o", "--output", action="store", help = "Output filename") +parser.add_argument("-q", "--quiet", action="store_true", help = "Do not print the banner on startup") + +args = parser.parse_args() + +# Add user appended padding strings +if args.append_padding: + for item in args.append_padding.split(','): + if item != '': common_paddings.append(item) + + +# Create years list +def bad_years_input(): + parser.print_usage() + print('\nIllegal year(s) input. Acceptable years range: 1000 - 3200.\n') + sys.exit(1) + + +if args.years: + years = [] + + if args.years.count(',') == 0 and args.years.count('-') == 0 and args.years.isdecimal() and int(args.years) >= 1000 and int(args.years) <= 3200: + years.append(str(args.years)) + + elif args.years.count(',') > 0: + for year in args.years.split(','): + if year.strip() != '' and year.isdecimal() and int(year) >= 1000 and int(year) <= 3200: + years.append(year) + else: + bad_years_input() + + elif args.years.count('-') == 1: + years_range = args.years.split('-') + start_year = years_range[0] + end_year = years_range[1] + + if (start_year.isdecimal() and int(start_year) < int(end_year) and int(start_year) >= 1000) and (end_year.isdecimal() and int(end_year) <= 3200): + for y in range(int(years_range[0]), int(years_range[1])+1): + years.append(str(y)) + else: + bad_years_input() + else: + bad_years_input() + + +# Colors +LOGO = '\033[38;5;40m' +LOGO2 = '\033[38;5;41m' +GREEN = '\033[38;5;82m' +ORANGE = '\033[0;38;5;214m' +RED = '\033[1;31m' +END = '\033[0m' +BOLD = '\033[1m' + +def banner(): + + pad = ' ' + print('\n') + print(f'{pad}{LOGO}█▀▄ ▄▀▀ █ █ █▀▄ ▄▀▄ █▄█ ▄▀▄ ▄▀▀ █▄█') + print(f'{pad}{LOGO2}█▀ ▄██ ▀▄█ █▄▀ ▀▄▀ █ █ █▀█ ▄██ █ █{END}') + print('\t Created by t3l3machus\n') + + +# ----------------( Base Settings )---------------- # +mutations_cage = [] +mutations_final = [] +outfile = args.output if args.output else 'output.txt' +trans_keys = [] + +transformations = [ + {'a' : '@'}, + {'e' : '3'}, + {'g' : ['9', '6']}, + {'i' : ['1', '!']}, + {'o' : '0'}, + {'s' : ['$', '5']}, + {'t' : '7'} +] + +for t in transformations: + for key in t.keys(): + trans_keys.append(key) + +# Paddings +if (args.common_paddings_before or args.common_paddings_after) and not args.custom_paddings_only: + + common_paddings = [ + '12', '23', '34', '45', '56', '67', '78', '89', '90'\ + '123', '234', '345', '456', '567', '678', '789', '890',\ + '.', '!', ';', '?', '!@', '@#', '#$', '$%', '%^', '^&', '&*', '*(', '()', \ + '!@#', '@#$', '#$%', '$%^', '%^&', '^&*', '&*(', '*()', ')_+',\ + '1!1', '!@!', '@#@', '$$$', '!@#$%', '123!@#', '12345' + #'!!!', '@@@', '###', '$$$', '%%%', '^^^', '&&&', '***', '(((', ')))', '---', '+++' + ] + +elif (args.common_paddings_before or args.common_paddings_after) and (args.custom_paddings_only and args.append_padding): + common_paddings = [] + +elif not (args.common_paddings_before or args.common_paddings_after): + pass + +else: + parser.print_usage() + print('\nIllegal padding settings.\n') + sys.exit(1) + +if args.append_padding: + for val in args.append_padding.split(','): + if val.strip() != '' and val not in common_paddings: + common_paddings.append(val) + + +# ----------------( Functions )---------------- # +def evalTransformations(w): + + trans_chars = [] + total = 1 + c = 0 + + w = list(w) + for char in w: + for t in transformations: + if char in t.keys(): + trans_chars.append(c) + if isinstance(t[char], list): + total *= 3 + else: + total *= 2 + c += 1 + + return [trans_chars, total] + + + +def mutate(tc): + + global trans_keys, mutations_cage, mutations_final + + i = trans_keys.index(args.word[tc].lower()) + trans = transformations[i][args.word[tc].lower()] + limit = len(trans) * len(mutations_cage) + c = 0 + + for m in mutations_cage: + w = list(m) + + if isinstance(trans, list): + for tt in trans: + w[tc] = tt + transformed = ''.join(w) + mutations_cage.append(transformed) + c += 1 + else: + w[tc] = trans + transformed = ''.join(w) + mutations_cage.append(transformed) + c += 1 + + if limit == c: break + + return mutations_cage + + + +def mutations_handler(trans_chars, total): + + global mutations_cage, mutations_final + + container = [] + + for word in mutations_final: + mutations_cage = [word.strip()] + for tc in trans_chars: + results = mutate(tc) + container.append(results) + + for m_set in container: + for m in m_set: + mutations_final.append(m) + + mutations_final = unique(mutations_final) + + with open(outfile, 'w') as wordlist: + for m in mutations_final: + wordlist.write(m + '\n') + + + +def grab_wordlist(): + + wordlist = open(outfile, 'r') + words = wordlist.readlines() + wordlist.close() + return words + + + +def mutateCase(word): + trans = list(map(''.join, itertools.product(*zip(word.upper(), word.lower())))) + return trans + + + +def caseMutationsHandler(word): + + case_mutations = mutateCase(word) + + for m in case_mutations: + mutations_final.append(m) + + + +def unique(l): + + unique_list = [] + + for i in l: + if i not in unique_list: + unique_list.append(i) + + return unique_list + + + +def mutate_years(): + + current_mutations = mutations_final.copy() + + with open(outfile, 'a') as wordlist: + for word in current_mutations: + for y in years: + wordlist.write(f'{word}{y}\n') + wordlist.write(f'{word}_{y}\n') + wordlist.write(f'{word}{y[2:]}\n') + mutations_final.append(f'{word}{y}') + mutations_final.append(f'{word}_{y}') + mutations_final.append(f'{word}{y[2:]}') + + + +def append_paddings_before(): + + current_mutations = mutations_final.copy() + wfilter = [] + + with open(outfile, 'a') as wordlist: + for word in current_mutations: + for val in common_paddings: + if f'{val}{word}' not in wfilter: + wordlist.write(f'{val}{word}\n') + wfilter.append(f'{val}{word}') + + if f'{val}_{word}' not in wfilter: + wordlist.write(f'{val}_{word}\n') + wfilter.append(f'{val}_{word}') + + + +def append_paddings_after(): + + current_mutations = mutations_final.copy() + wfilter = [] + + with open(outfile, 'a') as wordlist: + for word in current_mutations: + for val in common_paddings: + if f'{word}{val}' not in wfilter: + wordlist.write(f'{word}{val}\n') + wfilter.append(f'{word}{val}') + + if f'{word}_{val}' not in wfilter: + wordlist.write(f'{word}_{val}\n') + wfilter.append(f'{word}_{val}') + + + +def calculate_output(): + + global trans_keys + + c = 0 + total = 1 + basic_total = 1 + basic_size = 0 + size = 0 + + # Basic mutations calc + for char in args.word: + if char in trans_keys: + i = trans_keys.index(args.word[c].lower()) + trans = transformations[i][args.word[c].lower()] + basic_total *= (len(trans) + 2) + else: + basic_total *= 2 + + c += 1 + + total = basic_total + basic_size = total * (len(args.word) + 1) + size = basic_size + + # Adding years mutations calc + if args.years: + patterns = 3 + year_chars = 4 + _year = 5 + year_short = 2 + yrs = len(years) + size += (basic_size * patterns * yrs) + (basic_total * year_chars * yrs) + (basic_total * _year * yrs) + (basic_total * year_short * yrs) + total += total * len(years) * 3 + basic_total = total + basic_size = size + + # Common paddings mutations calc + patterns = 2 + + if args.common_paddings_after or args.common_paddings_before: + paddings_len = len(common_paddings) + pads_wlen_sum = sum([basic_total*len(w) for w in common_paddings]) + _pads_wlen_sum = sum([basic_total*(len(w)+1) for w in common_paddings]) + + if args.common_paddings_after and args.common_paddings_before: + size += ((basic_size * patterns * paddings_len) + pads_wlen_sum + _pads_wlen_sum) * 2 + total += (total * len(common_paddings) * 2) * 2 + + elif args.common_paddings_after or args.common_paddings_before: + size += (basic_size * patterns * paddings_len) + pads_wlen_sum + _pads_wlen_sum + total += total * len(common_paddings) * 2 + + return [total, size] + + + +def chill(): + pass + + + +def main(): + + banner() if not args.quiet else chill() + + # Calculate output size + total_size = calculate_output() + concent = input(f'[{ORANGE}Warning{END}] This operation will produce a total of {BOLD}{total_size[0]}{END} words, {BOLD}{total_size[1]}{END} bytes (if no duplicates occur). Are you sure you want to proceed? [y/n]: ') + + if concent.lower() not in ['y', 'yes']: + sys.exit(f'\n[{RED}X{END}] Aborting.') + + else: + # Produce case mutations + print(f'[{GREEN}*{END}] Producing character case-based transformations... ') + caseMutationsHandler(args.word) + + # Produce char substitution mutations + print(f'[{GREEN}*{END}] Mutating word based on commonly used character-symbol substitutions... ') + trans = evalTransformations(args.word) + mutations_handler(trans[0], trans[1]) + + # Handle years + if args.years: + print(f'[{GREEN}*{END}] Appending transformations based on given year(s) values... ') + mutate_years() + + # Append common paddings + if args.common_paddings_after: + print(f'[{GREEN}*{END}] Appending common paddings after each word mutation... ') + append_paddings_after() + + if args.common_paddings_before: + print(f'[{GREEN}*{END}] Appending common paddings before each word mutation... ') + append_paddings_before() + + print(f'[{GREEN}*{END}] Completed! List saved in {outfile}') + + +if __name__ == '__main__': + main()