0

I have been trying to create a password generator in python using the secrets module. I first ask the user the desired length of the password, and then chose randomly between 3 lists of characters (letters, numbers, symbols). I then print the results one by one through a loop.

My problem is that the program works fine until around 12 characters asked by the user. I then get the following error IndexError: list index out of range and after searching for hours, I can't manage to find an answer.

Sorry if the question seems basic, but I'm still a beginner, and only want to improve!

Here's my code :

import secrets
# importing modules

doRun = True
while doRun:
    length = int(input("How many characters do you want you password to have ? "))
    # Asking the user for the length of the password

    letCar = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
              "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
              "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
    # List for characters
    numCar = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
    # List for numbers
    symCar = ["!", "@", "?"]
    # List for symbols
    password = []
    # Initializing list for password

    for i in range(0, length):
        selector = secrets.randbelow(3)
        # Randomly choosing from which list to pick
        if selector == 0:
            # Characters list
            chosenCar = secrets.choice(letCar)
            password.append(chosenCar)
            letCar.remove(chosenCar)
        elif selector == 1:
            # Numbers list
            chosenCar = secrets.choice(numCar)
            password.append(chosenCar)
            numCar.remove(chosenCar)
        elif selector == 2:
            # Symbols list
            chosenCar = secrets.choice(symCar)
            password.append(chosenCar)
            symCar.remove(chosenCar)

    print("password is : ", end="")
    for i in range(len(password)):
        print(password[i], end="")
    print()
    doRun = input("Again ? (Yes --> True // No --> False) : ")

The errors are :

Traceback (most recent call last):
  File "E:\Bureautique\Outils\Programmation\Python\Projects\PWHash\main.py", line 35, in <module>
    chosenCar = secrets.choice(symCar)
  File "C:\Users\Arthur\AppData\Local\Programs\Python\Python39\lib\random.py", line 347, in choice
    return seq[self._randbelow(len(seq))]
IndexError: list index out of range

Thank you for your help!

5
  • What was the chosen value of length that triggered the error? Commented Apr 5, 2021 at 17:37
  • It starts giving errors when length >= 10, but not everytime. This is what intrigues me, it sometimes prints the result, and sometimes returns an error. I also get errors for lower values, but it seems to be more rare. Commented Apr 5, 2021 at 17:39
  • Zakariyya is right. Also, if you're trying to generate passwords, you're better off putting all the characters in one big list instead of splitting it up, and also don't remove any characters from the list. The best passwords are unpredictable: by removing characters, you're making it easier to guess what the next character is (it can't be any of the characters that were already in the password) and by putting the characters in different lists, you make special characters way more likely to appear than letters Commented Apr 5, 2021 at 17:42
  • Well, you are removing items from the lists randomly, so it could crash after 4 times if you remove all of the elements from symCar but the lists could last longer if there is heavy sampling from a longer list like letCar. Commented Apr 5, 2021 at 17:45
  • Yes, that will probably work ! Also, thank you for your advice, I will modify this to make the program stronger and less predictable. In any way, the program wasn't supposed to be used on a daily basis, but was more of a project idea I had that I thought would be fun to do. Commented Apr 5, 2021 at 17:46

3 Answers 3

1

I think it's because you're removing items from the Car lists, so that when a Car is chosen enough times, in the case of the symCars, the line where your program crashed, only 3, and it is then an empty list, so if the Car is selected again there's nothing in the list for the secrets module to find

Sign up to request clarification or add additional context in comments.

1 Comment

Indeed, that might correct the problem, I did not think about this case ! I will try correcting it and will get back to you afterwards. Thank you very much !
0

I don't know if it's what you're looking for but that's how it worked for me

for i in range(0, length):
        selector = secrets.randbelow(3)
        # Randomly choosing from which list to pick
        if selector == 0:
            # Characters list
            chosenCar = secrets.choice(letCar[i])
            password.append(chosenCar)
            letCar.remove(chosenCar)
        elif selector == 1:
            # Numbers list
            chosenCar = secrets.choice(numCar[i])
            password.append(chosenCar)
            numCar.remove(chosenCar)

Comments

0

The problem is that an item from symCar is deleted every time an item is selected from it. This empties the list after three repetitions. To fix the problem, you could remove the .remove lines. Although this allows for multiple of a single character to be included in your password, this helps keep it unpredictable.

Another option is to add a way for the lists to refill after all of their items have been deleted. An example of this is shown below.

if symCar == []:
    symCar = ["!", "@", "?"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.