Skip to content
Advertisement

How to disable list elements for one cycle?

I wrote a password generation script, it ensures that 2 characters of the same type cannot appear behind each other: “12” or “ab” are not possible. It always have to be different types, like “1a” or “a%” or “aB”.

I currently use this to achieve it:

# l1 - l4 are the last 4 symbols, l5 the current.
# n1 - n5 are just ones and zeros, depending if l on that position is a number
# For the problem I describe here just l5 and l4 would be necessary, but I have different 'policies',
# if you want 2 or 3 characters of the same type behind each other

if (l1.isupper() and l2.isupper()) or   # characters upper
        (l2.isupper() and l3.isupper()) or 
        (l3.isupper() and l4.isupper()) or 
        (l4.isupper() and l5.isupper()) or 
        (l1.islower() and l2.islower()) or 
        (l2.islower() and l3.islower()) or 
        (l3.islower() and l4.islower()) or 
        (l4.islower() and l5.islower()) or   # characters lower 
        (n1 and n2) or (n2 and n3) or (n3 and n4) or (n4 and n5):  # consecutive numbers
    return False

While it does work its rather slow, because if the function returns False a new random character is sampled and tested again until a valid character is found.

I have thought about instead of having one giant string of characters ,

char_list = ['A', ...'Z', 'a', ...'z', '0', ...'9', '!', ...'+']  # !...+ are symbols like !ยง$ and others

I could split it into types, like so:

char_list = [['A', ...'Z'], ['a', ...'z'], ['0', ...'9'], ['!', ...'+']]

The generator could pick one of the lists, then sample a character and simply disable this type for the next iteration. This should be much faster because it wouldn’t be possible to have the same type twice in a row. I however have no idea how to implement this ‘disable for one cycle’ thing.

Full code: https://pastebin.com/ZJkaKcni

Advertisement

Answer

Well you could do something like this, I’m sure it is not the most performance optimized solution but is fairly fast, although I don’t know what is slow/fast for your usecase:

import random
import string


def generate_password(length):
    password = ""
    char_pools = [
        string.ascii_lowercase,
        string.ascii_uppercase,
        string.digits,
        string.punctuation,
    ]

    prev_pool = None
    pool = random.choice(char_pools)
    for _ in range(length):
        while pool == prev_pool:
            pool = random.choice(char_pools)
        password += random.choice(pool)
        prev_pool = pool

    return password

From cryptographic perspective though I’m not sure if this is a safe solution, since you already give a hint to the attacker. If they could identify a character from the password, they were able to presume the next set of possible characters which can lead to a decryption already faster than a brute-force attack.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement