16

I am trying to create a system that requires you to enter a password. If it is all lower, upper or num then print weak, if it is two of the conditions, then it is med and if all have been met it is strong. It just does not seem to work.

The weak and strong work however the medium does not.

I do not know where I have gone wrong.

def password():

    print ('enter password')
    print ()
    print ()
    print ('the password must be at least 6, and no more than 12 characters long')
    print ()

    password = input ('type your password    ....')


    weak = 'weak'
    med = 'medium'
    strong = 'strong'

    if len(password) >12:
        print ('password is too long It must be between 6 and 12 characters')

    elif len(password) <6:
        print ('password is too short It must be between 6 and 12 characters')


    elif len(password)    >=6 and len(password) <= 12:
        print ('password ok')

        if password.lower()== password or password.upper()==password or password.isalnum()==password:
            print ('password is', weak)

        elif password.lower()== password and password.upper()==password or password.isalnum()==password:
            print ('password is', med)

        else:
            password.lower()== password and password.upper()==password and password.isalnum()==password
            print ('password is', strong)
ChrisF
  • 134,786
  • 31
  • 255
  • 325
user2412839
  • 171
  • 1
  • 1
  • 5

6 Answers6

43

Holá
The best approach is using regular expression search
Here is the function I am currently using

def password_check(password):
    """
    Verify the strength of 'password'
    Returns a dict indicating the wrong criteria
    A password is considered strong if:
        8 characters length or more
        1 digit or more
        1 symbol or more
        1 uppercase letter or more
        1 lowercase letter or more
    """

    # calculating the length
    length_error = len(password) < 8

    # searching for digits
    digit_error = re.search(r"\d", password) is None

    # searching for uppercase
    uppercase_error = re.search(r"[A-Z]", password) is None

    # searching for lowercase
    lowercase_error = re.search(r"[a-z]", password) is None

    # searching for symbols
    symbol_error = re.search(r"[ !#$%&'()*+,-./[\\\]^_`{|}~"+r'"]', password) is None

    # overall result
    password_ok = not ( length_error or digit_error or uppercase_error or lowercase_error or symbol_error )

    return {
        'password_ok' : password_ok,
        'length_error' : length_error,
        'digit_error' : digit_error,
        'uppercase_error' : uppercase_error,
        'lowercase_error' : lowercase_error,
        'symbol_error' : symbol_error,
    }

EDIT:
Fallowing a suggestion of Lukasz here is an update to the especial symbol condition verification

symbol_error = re.search(r"\W", password) is None
ePi272314
  • 12,557
  • 5
  • 50
  • 36
  • For the symbol_error is there a way to use '\W*\s'? Listing out the symbols doesn't seem that efficient. For instance the list that you provide omits ?, <, > and many others. – Lukasz Jan 04 '16 at 20:33
  • Thanks for your comment Lukasz. The search for symbols could be simplified with the use of the special sequence \W. There is no need to include \s because the space is already included in \W. Thus the code for "searching for symbols" must be changed to: symbol_error = re.search(r"\W", password) is None – ePi272314 Jan 08 '16 at 21:40
  • I like this approach. Clear, simple and very readable. Not sure you want to allow for spaces in the password though? Although the opinions on that seem to differ: https://security.stackexchange.com/questions/32691/why-not-allow-spaces-in-a-password – Hans Bouwmeester Dec 05 '18 at 20:10
  • 3
    at least leading and trailing space should error: `o.whitespace_error = len(pwd.strip()) != len(pwd)` – kxr Dec 11 '19 at 16:48
  • 1
    Don't forget to add import re at the start ;) – Jose Machado Aug 16 '22 at 22:52
6

password.isalnum() returns a boolean, so password.isalnum()==password will always be False.

Just omit the ==password part:

if password.lower()== password or password.upper()==password or password.isalnum():
    # ...

Next, it can never be both all upper and lower, or all upper and numbers or all lower and all numbers, so the second condition (medium) is impossible. Perhaps you should look for the presence of some uppercase, lowercase and digits instead?

However, first another problem to address. You are testing if the password is alphanumeric, consisting of just characters and/or numbers. If you want to test for just numbers, use .isdigit().

You may want to familiarize yourself with the string methods. There are handy .islower() and .isupper() methods available that you might want to try out, for example:

>>> 'abc'.islower()
True
>>> 'abc123'.islower()
True
>>> 'Abc123'.islower()
False
>>> 'ABC'.isupper()
True
>>> 'ABC123'.isupper()
True
>>> 'Abc123'.isupper()
False

These are faster and less verbose that using password.upper() == password, the following will test the same:

if password.isupper() or password.islower() or password.isdigit():
    # very weak indeed

Next trick you want to learn is to loop over a string, so you can test individual characters:

>>> [c.isdigit() for c in 'abc123']
[False, False, False, True, True, True]

If you combine that with the any() function, you can test if there are some characters that are numbers:

>>> any(c.isdigit() for c in 'abc123')
True
>>> any(c.isdigit() for c in 'abc')
False

I think you'll find those tricks handy when testing for password strengths.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

Here is a remake of what you wrote:

import re

def password():
    print ('Enter a password\n\nThe password must be between 6 and 12 characters.\n')

    while True:
        password = input('Password: ... ')
        if 6 <= len(password) < 12:
            break
        print ('The password must be between 6 and 12 characters.\n')

    password_scores = {0:'Horrible', 1:'Weak', 2:'Medium', 3:'Strong'}
    password_strength = dict.fromkeys(['has_upper', 'has_lower', 'has_num'], False)
    if re.search(r'[A-Z]', password):
        password_strength['has_upper'] = True
    if re.search(r'[a-z]', password):
        password_strength['has_lower'] = True
    if re.search(r'[0-9]', password):
        password_strength['has_num'] = True

    score = len([b for b in password_strength.values() if b])

    print ('Password is %s' % password_scores[score])

Output (sample):

>>> password()
Enter a password

The password must be between 6 and 12 characters.

Password: ... ghgG234
Password is Strong
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
  • Switch `raw_input` to `input` and you are good to go, and visa-versa if using python 2. (I already edited my answer, so it should be good to go) – Inbar Rose May 23 '13 at 09:29
1

I was also looking for some password strength examine function, and found lot of half-worked suggestion. I assemblied my own function based on ones.

hope to help

def get_pw_strength( pw ):

    s_lc = set(['a', 'c', 'b', 'e', 'd', 'g', 'f', 'i', 'h', 'k', 'j', 'm', 'l', 'o', 'n', 'q', 'p', 's', 'r', 'u', 't', 'w', 'v', 'y', 'x', 'z'])
    s_uc = set(['A', 'C', 'B', 'E', 'D', 'G', 'F', 'I', 'H', 'K', 'J', 'M', 'L', 'O', 'N', 'Q', 'P', 'S', 'R', 'U', 'T', 'W', 'V', 'Y', 'X', 'Z'])
    s_dg = set(['1', '0', '3', '2', '5', '4', '7', '6', '9', '8'])
    s_sp = set(['+', ',', '.', '-', '?', ':', '_', '(', ')', '*', '/', ';', '+', '!'])
    pw_s = 0
    pw_steps = (5, 8, 12) 

    pw_l = len(pw)
    if ( pw_l < 4 ):
        return 0
    for l in pw_steps :
        if ( pw_l > l ):
            pw_s += 1
            #print "length over ", l," giving point", pw_s

    c_lc = c_uc = c_dg = c_sp = 0
    for c in pw :
        if ( c in s_lc ) :
            c_lc += 1
        if ( c in s_uc ) :
            c_uc += 1
        if ( c in s_dg ) :
            c_dg += 1
        if ( c in s_sp ) :
            c_sp += 1
    if ( c_lc + c_uc + c_dg + c_sp  <> pw_l ):
        #print c_lc, c_uc, c_dg, c_sp, pw_l
        #raise Exception "Forbidden chracter"
        return -1
    charset = 0
    if ( c_lc ) :
        pw_s += 1
        charset = len(s_lc)
    if ( c_uc ) :
        pw_s += 1
        charset = len(s_uc)
    if ( c_dg ) :
        pw_s += 1
        charset = len(s_dg)
    if ( c_sp ) :
        pw_s += 2
        charset = len(s_sp)
    entropy = log(pow(charset,pw_l),2)

    return pw_s, entropy
indivisible
  • 4,892
  • 4
  • 31
  • 50
milan
  • 11
  • 1
1

Here my custom python function to check password strength with the requirement of certain character length, contains letter, number and symbol (or special character), keystroke input from an ASCII keyboard. I use python 3.9, and use python built in function, I mean without importing other function or modules like "Re", etc. I use python isalpha() for checking letter, isdigit() to check number and not isalpha() to check for symbol or special characters understanding that in ASCII keyboard other than alphanumeric is symbol.

def validate(password):
    a_set = set()
    min_length = 8
    if len(password) < min_length:
        print("Insufficient length")
        return False
    for char in password:
        # Checking alphabet: a-z A-Z is in password characters
        if char.isalpha() == True:
            a_set.add("letter")
            continue
        # Check for numbers 0-9
        elif char.isdigit() == True:
            a_set.add("number")
            continue
        # Check for symbol (not alphanumeric)
        elif char.isalnum() == False:
            a_set.add("symbol")
            continue
        else:
            print("User may use a non ASCII keyboard!")
            return False
    # Check if all: letter, number and symbol in the set
    if "letter" not in a_set:
        print("No letter in password!")
        return False
    elif "number" not in a_set:
        print("No number in password!")
        return False
    elif "symbol" not in a_set:
        print("No symbol in password!")
        return False
    else:
        print("Password is good. Carry on.")
        return True
  • With password = "abc123%", validate(password) print "insufficient password length" return False
  • With password = "12398*&97$3!", validate(password) print "no letter" return False
  • With password = "jUkse*%@+", validate(password) print "no number" return False
  • With password = "alPhAn78eric", validate(password) print "no symbol" return False
  • With password = "1a2B#c*+9", validate(password) print "Password is good" return True
KokoEfraim
  • 198
  • 8
-1

you can write a simple "if statement" to check "strength of a password" , and you can use it where you want and change it based on your requirements :

password = "mypassword_Q@1"

if len(password) < 8 or password.lower() == password or password.upper() == password or password.isalnum()\
        or not any(i.isdigit() for i in password):
    print('your password is weak ')

else:
    print('your password is strong ')

i hope this helpful

K.A
  • 1,399
  • 12
  • 24