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.