ASCII Password validating in Python - python

I have a task for my college (I am beginner), which asks you to validate a password using ASCII characters. I tried using simple code and it worked, however it kept skipping my ASCII part.
Requirement list:
1.4 Call function to get a valid password OUT: password
1.4.1 Loop until password is valid
1.4.2 Ask the user to enter a password
1.4.3 Check that the first character is a capital letter (ASCII values 65 to 90)
1.4.4 Check that the last character is #, $ or % (ASCII values 35 to 37) 1.4.5 Return a valid password
U = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
upCase = ''.join(chr(i) for i in U)
print(upCase) #Ensure it is working
def passVal(userPass):
SpecialSym = ["#", "$", "%"]
val = True
#Common way to validate password VVV
if len(userPass) < 8:
print("Length of password should be at least 8")
val = False
if not any(char.isdigit() for char in userPass):
print("Password should have at least one numeral")
val = False
#I Tried same with ASCII (and other methods too) but it seemed to be skipping this part VVV
if not any(upCase for char in userPass):
print("Password should have at least one uppercase letter")
val = False
if not any(char.islower() for char in userPass):
print("Password should have at least one lowercase letter")
val = False
if not any(char in SpecialSym for char in userPass):
print("Password should have at least on fo the symbols $%#")
val = False
if val:
return val
def password():
if (passVal(userPass)):
print("Password is valid")
else:
print("Invalid Password !!")
userPass = input("Pass: ")
password()

From Python 3.7 you can use str.isascii()...
>>> word = 'asciiString'
>>> word.isascii()
True
Otherwise you could use:
>>> all([ord(c) < 128 for c in word])
True
Since all ASCII characters have an ordinal (ord) value less than 128 (0 -> 127): https://en.wikipedia.org/wiki/ASCII
So your logic will either be (3.7+):
if word.isascii():
# string is ascii
...
Or:
if all([ord(c) < 128 for c in word]):
# string is ascii
else:
# string contains at least one non-ascii character

Related

Counting valid passwords in a list

I have a list
passwords = ['baCr',
'/)T.I]DdLNh)^WRIDa_z1',
'izM!Imi',
'NOb5VEhw$[17Q{P',
'i',
'J$52UY$Y',
'T',
'3',
'{77Vt3=2WOCpKWN?',
'$*K',
'H2#u.yUON(i;?',
'zr',
'/}YrhZ7T,X^/}cM0BvR#S)Le$/$Yg#',
'XUGc%',
'+$?D]',
'4?!-G}',
'iMI!G5q]bwI-fE1VT{8rsHWX2tk$29',
'E#',
'lVSh;W9:RyM%Zl9L*;',
'vWYJ%-v?^d:(o',
'.(tp?Hxu{[D+cAhmXGM{ahV3a_fZ!',
'3SXUCASo8/3psxL0p5mw=uf',
'%%7h',
'e(d',
'Ef98S2EUy)mT9MU{#F:zE^8Pb]mg)k',
'k',
'ji[Wtw.#9F$GN%ymi-FU',
'HX?z74lGp]TLqlGp[cRV!w(5]s?7m9',
'5eL',
'Zcrod:Xm',
'}t8bj:RJ4BA6i+x$PlbKL$NNIj',
'H)u(7{lK?Mk!cvUBkzlHXfFyeTL%Sh',
'/]AA-R0A',
'Qq1L$:(s',
'HoDUEPlaKAnDo2;W5}FlY)H(9I',
't0UVz3xgM2Js',
'XJ=#Y=P)z#%7',
'hnDTB7vtCa!MsAIR',
'{R/BvTB?iNS!vKntp$,tvwIC7',
'}2Lz.K',
'P9?+AgbGhp${uMoLqwS(aajG9P.b',
'eldDgR6SZ:v6w^G6ru*vo-',
'-{2{4',
'A=',
'Z{G2p{-#Kz/c}8utFm=WPH_:uTQiT',
'Ql91',
'9R.6J#Y.jWs/}XA0TV4%uRi_k43',
'zcy.Vqfk2xpwgNt-KW?$m',
'X+O+NGT}',
'}]2_',
'Mcuz1;xCE{iHRhsO695ef',
';Q4!nRV7[,LvLDRjke1',
'3BJi9XZW',
'+Rot!',
'nP.kqo1-g2G8ZT$2wxRwI8MAMJ',
'^,$^F7:X=DkDUa?3,L{wf',
'56',
'#O/7CHV4WoMRmq^j$J$/Hk6DUD',
'WkWI5O1J017)5.%!dAaVLhoW',
')$;',
'{5QjA.g:xO#P1',
'M]J%Dxc2]xxc1Kyn7=Ga+sx!#-B9',
':WA',
'2?#',
'HwH_sUUd-i$ln178038#kiQ7T#kZ;',
'13}VI',
'QV+',
'2r-%+=:V',
'DM(DYS),Z==A}',
'fhtmcFtG)CQY0YrB7Aq%0Oogv]g',
'-WFuVnPpZ?z#E{H3I#_:h-v^w9K',
'ceg4g-Y',
'yK8D5*om',
'_ic55w$6N/3/00c',
'^*BhAG4m',
'w#PW',
'D%=^j}l/Qr1l#V*%8d',
'6tJNCnrx,)Fv6*+;q.;PCx1);',
'}Q?}pvhv=beW',
'W$$.C5cI9;Grs653}-5(#p/Nb#8i',
'{(:F6LI',
'r]l#?Fy',
'#N4[qs{!P{Kb[t_sB',
'xoL:UAe(7m$4gjtuakk-ViLNu^b',
'Hc]1:eqc%TzXy8n-?s7VQG.#[nm',
'sM:pqfC',
'8XVO5X7lwt8!B6',
'{$[^',
'7SiL3',
'hV_yN(Kh19%M)5PDV)9oQ5?y*k%2',
'}UhE!SxN7qQVdiNXuw8N+Xxio%I',
'KK:',
'+ZsrD?az!I',
'#_',
'roX:*+2Dl##k-io',
'7Dq',
'TBQ[5',
'9/CX',
'e74j*J^oD',
'1KRmy=FjO[P?kd#+zNQV9:uL(vP',
'di?hp0L*6VZf9:',
'24?%6GW%',
'S#',
'hI7TS!Jo2J2$Zp/_^aIK^(v{K4+',
'W*zIb',
'Qlu#bPU6UtNd',
'n9yX]z0xBQ3C$BG4Jk/,#MG4j[',
'u',
'xL!b.A!zUn',
'I21%',
'ff1Vf=fWqL:sg$gfKnA7;R',
'!6A#W!jwnB-fPP1hGK]sA!B#uitkj',
'qNf.B35u0),}eL)',
'gXB.8I$bQ',
'9v2q0An',
'F?9HZ4',
'z]bgZ8wHsLJQvT!gh(Yn5o[',
'w)K{[3{Z0%u^q',
'SD',
'#c)RM554mY!YD93',
'09YNkm.#VyMPC8cQg5',
'R1}Jw!-rV=Bo{A9#/aWuuP',
'n/CC5xU3hC.itVaF,R=?[^',
'[RiM[xNb',
'=I',
':M[Z%WY,w0.:{c;69ESv_#4S)#n',
'D6-9s.,f=pXiuMF;!l}!N]',
'L?2',
'=#l4,5',
'ZAdAEkQzdmc[O[A,H%9]3}i?',
'0%,OVJ9/}([L[Nq=3mgS:sYHa;',
'Y4:*NU',
'$To.Ce7:hd#YgKFZr+1i.Lx)BIuH',
'nM)#%*H9GiXevMmVm.(Z)]:!BxU!r',
'h?(Y_',
'F(qqHrvx5kL[Xx=4lcs:H!A',
'TgIT+I;GClgST/NB*',
'6=}.',
'+4',
'+BQ5C}:6',
'Dh5VF2Ek#a',
'REB4k%v.c1J*vq?F3#2',
'8}JCK',
'#{?2[X?M[A!_O]RVKqVv%93_#]vx,$',
'H44z_DwaG/A,g)xBCG+9GjAh7e]$!',
'jgct7fezi;jtqc*',
'(_',
'.3:',
'eM4mx)S9HDq_,*rZ;LE0S=U4L2i',
'-]F]']
and I need to find passwords meeting all of the following criteria:
Must not contain any more than 15 characters
Cannot contain any lowercase characters (a-z)
The first and last character cannot be the same
This is my code:
valid=0
for password in passwords:
if len(password)<=15 and password.upper() and password[0]!=password[-1]: valid+=1
I believe the answer is 38, but I keep getting 85? Does anyone see an error in my code that would return the wrong answer? Thanks.
password.upper() returns the password in caps. You need to check they are the same with password.upper() == password:
valid = 0
for password in passwords:
if len(password) <= 15 and password.upper() == password and password[0] != password[-1]:
valid += 1
>>> valid
38
You can see what is happening here:
>>> x = "abc"
# Check the truthiness of x (this is what you were originally doing)
# A non-empty string is always True
>>> bool(x)
True
# x.upper() will just return an uppercase copy
>>> x.upper()
'ABC'
# You need to compare the original with the upper
>>> bool(x == x.upper())
False
You could use a regex to check if no lowercase characters (a-z) are present:
import re
passwords = [
'baCr',
'/)T.I]DdLNh)^WRIDa_z1',
'izM!Imi',
'NOb5VEhw$[17Q{P',
'i',
...
]
valid = 0
for password in passwords:
if len(password) <= 15 and not re.search('[a-z]', password) and password[0] != password[-1]:
valid += 1
print(f'{valid = }')
Output:
valid = 38
Another version:
import re
valid, pat = 0, re.compile(r"([^a-z])[^a-z]{,13}[^\1a-z]$")
for p in passwords:
valid += bool(pat.match(p))
print(valid)
Prints:
38

Added an else statement inside a for loop, and now only the else part prints even when if is true

This is my first ever computer science course so forgive me if this answer is really obvious. I wrote the below code and it worked just fine. I just needed to add an else statement to account for an invalid name input.
Here is is before:
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
name = input("Please enter a name:")
And here it is after:
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
else:
print("That name is not in this class.")
name = input("Please enter a name:")
name = input("Please enter a name:")
It just keeps printing "That name is not in this class." no matter what I type in. SOS
The if statement is evaluated each time through the loop, so you need to keep track of whether the name has been found, and then only print at the end.
For example:
while name!='q':
found = False
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
found = True
break
if not found:
print("That name is not in this class.")
name = input("Please enter a name:")
I think you will really benefit here from using a dictionary. See the following example.
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name_score_map = dict(zip(mynames, myscores))
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
if name in name_score_map:
print(name, "scored", name_score_map[name])
else:
print("That name is not in this class.")
name = input("Please enter a name:")
In the first line, we construct a dictionary that maps the name of a student to the score they got. This takes away the need to iterate through the mynames list to see if a name is in it and then using the corresponding index to grab the score. This, in effect, removes the issue you were facing with print("That name is not in this class.") executing for every iteration in which mynames[x] != name.
We can then check if the name has a score by seeing if the name is in name_score_map. This reduces the time complexity of the search from O(n) to O(1). We can then grab score simply by using the name as a key to the name_score_map dictionary.

How to decode prefix codes efficiently with Python?

I am trying to decode a Huffman encoded string, with the following script:
def decode(input_string, lookup_table):
codes = lookup_table.keys()
result = bytearray()
i = 0
while len(input_string[i:]) != 0:
for code in codes:
if input_string[i:].startswith(code):
result.append(lookup_table[code])
i += len(code)
break
return ''.join((chr(x) for x in result))
lookup_table = {'10': 108, '00': 111, '0111': 114, '010': 119, '0110': 72, '1111': 33, '1110': 32, '1100': 100, '1101': 101}
input_string = '0110110110100011100100001111011001111'
print decode(input_string, lookup_table)
This script gives as output:
'Hello world!'
The script works for this small string, but decoding an encoded version of Hamlet takes 110 seconds. Is there a more efficient and faster way to do this?

If and elif statements act as if "if" and "elif" are not there [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 5 years ago.
While writing a project for fun, I came across an unfamiliar issue with If and Elif statements. For some reason when the user inputs a dog "type", python ignores the if statements and continues on using the rest of the statement. The program was written in Python 3.6. I have no clue as to why the if and elif statements aren't working properly. Is there a formatting/syntax issue that I am not aware of? Thanks in advance!
def small():
small_list = [0, 15, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80]
small_input = input("How old is your dog?")
print(small_input)
small_age = int(small_input)
small_set2 = small_list[small_age]
print("Your dog's age is: " + str(small_set2))
def medium():
medium_list = [0, 15, 24, 28, 32, 36, 42, 47, 51, 56, 60, 65, 69, 74, 78, 83, 87]
medium_input = input("How old is your dog?")
print(medium_input)
medium_age = int(medium_input)
medium_set2 = medium_list[medium_age]
medium_set2 = str(medium_set2)
print("Your dog's age is: " + str(medium_set2))
def large():
large_input = input("How old is your dog?")
print(large_input)
large_set = [0, 15, 24, 28, 32, 36, 45, 50, 55, 61, 66, 72, 77, 82, 88, 93, 120]
large_age = int(large_input)
large_set2 = large_set[large_age]
large_set2 = str(large_set2)
print("Your dog's age is: " + str(large_set2))
def dog():
dog1 = input('What size dog do you have?')
print(dog1)
if dog1 == 'Small' or 'small':
print("Okay, you have a small dog.")
small()
elif dog1 == 'Medium' or 'medium':
print("Okay, you have a medium dog.")
medium()
elif dog1 == 'Large' or 'large':
print("Okay, you have a large dog.")
large()
else:
print("Sorry, I did not understand that.")
dog()
dog()
if dog1 == 'Small' or 'small':
This statement parses as:
if (dog1 == 'Small') or ('small'):
Because non-empty strings are always truthy, this is equivalent to:
if (dog1 == 'Small') or True:
So the condition is always met.
You probably want this instead:
if dog1 in ('Small', 'small'):
Or even better (ignore all the capitalisation issues):
if dog1.lower() == 'small':

SHA 512 crypt output written with Python code is different from mkpasswd

Running mkpasswd -m sha-512 -S salt1234 password results in the following:
$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81
I have this snippet of Python code that I thought would output the same, but isn't:
import hashlib, base64
print(base64.b64encode(hashlib.sha512('password' + 'salt1234').digest()))
It instead results in:
nOkBUt6l7zlKAfjtk1EfB0TmckXfDiA4FPLcpywOLORZ1PWQK4+PZVEiT4+9rFjqR3xnaruZBiRjDGcDpxxTig==
Not sure what I am doing wrong.
Another question I have is, how do I tell sha512 function to do custom rounds. It seems to take only 1 argument.
mkpasswd is a front-end to the crypt() function. I don't think it is a straight-forward SHA512 hash here.
A little research points to the specification for SHA256-crypt and SHA512-crypt, which shows the hash is applied a default 5000 times. You can specify a different number of rounds using the -R switch to mkpasswd; -R 5000 indeed gives you the same output:
$ mkpasswd -m sha-512 -S salt1234 -R 5000 password
$6$rounds=5000$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81
The minimum number of rounds offered by the command-line tool is 1000:
$ mkpasswd -m sha-512 -S salt1234 -R 999 password
$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//
$ mkpasswd -m sha-512 -S salt1234 -R 1 password
$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//
The algorithm is a bit more involved, requiring you to create several digests. You could instead access the C crypt() function through the crypt.crypt() function, and drive it the same way the mkpasswd commandline does.
It depends on your platform if the SHA512-crypt method is available; the Python 3 version of the crypt module offers a crypt.methods list that tells you what methods your platform supports. Since this use the exact same library mkpasswd uses, your OS obviously does support SHA512-crypt and Python will have access too.
You need to prefix the salt with '$6$ to specify the different method. You can specify the number of rounds by adding a 'rounds=<N>$' string between the '$6$' string and your salt:
import crypt
import os
import string
try: # 3.6 or above
from secrets import choice as randchoice
except ImportError:
from random import SystemRandom
randchoice = SystemRandom().choice
def sha512_crypt(password, salt=None, rounds=None):
if salt is None:
salt = ''.join([randchoice(string.ascii_letters + string.digits)
for _ in range(8)])
prefix = '$6$'
if rounds is not None:
rounds = max(1000, min(999999999, rounds or 5000))
prefix += 'rounds={0}$'.format(rounds)
return crypt.crypt(password, prefix + salt)
This then produces the same output as the mkpasswd command line:
>>> sha512_crypt('password', 'salt1234')
'$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
>>> sha512_crypt('password', 'salt1234', rounds=1000)
'$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//'
You need to use crypt.crypt:
>>> import crypt
>>> crypt.crypt('password', '$6$' + 'salt1234')
'$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
Here is a pure python3 implementation of the sha512_crypt function based on the specification. This is for illustration only, always use crypt.crypt instead!
import hashlib, base64
SHUFFLE_SHA512_INDICES = [
42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3, 4, 46, 25,
26, 5, 47, 48, 27, 6, 7, 49, 28, 29, 8, 50, 51, 30, 9,
10, 52, 31, 32, 11, 53, 54, 33, 12, 13, 55, 34, 35, 14, 56,
57, 36, 15, 16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40,
41, 20, 62, 63
]
def shuffle_sha512(data):
return bytes(data[i] for i in SHUFFLE_SHA512_INDICES)
def extend_by_repeat(data, length):
return (data * (length // len(data) + 1))[:length]
CUSTOM_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
''' Base64 encode based on SECTION 22.e)
'''
def custom_b64encode(data, alphabet = CUSTOM_ALPHABET):
buffer,count,result = 0,0,[]
for byte in data:
buffer |= byte << count
count += 8
while count >= 6:
result.append(buffer & 0x3f)
buffer >>= 6
count -= 6
if count > 0:
result.append(buffer)
return ''.join(alphabet[idx] for idx in result)
''' From http://www.akkadia.org/drepper/SHA-crypt.txt
'''
def sha512_crypt(password, salt, rounds_in = None):
rounds,rounds_defined = 5000, False
if rounds_in is not None:
rounds,rounds_defined = rounds_in, True
assert 1000 <= rounds <= 999999999
hash = hashlib.sha512
salt_prefix = '$6$'
password = password.encode('utf8')
salt = salt.encode('ascii')[:16]
A = hash() # SECTION 1.
A.update(password) # SECTION 2.
A.update(salt) # SECTION 3.
B = hash() # SECTION 4.
B.update(password) # SECTION 5.
B.update(salt) # SECTION 6.
B.update(password) # SECTION 7.
digestB = B.digest(); # SECTION 8.
A.update(extend_by_repeat(digestB, len(password))) # SECTION 9., 10.
# SECTION 11.
i = len(password)
while i > 0:
if i & 1:
A.update(digestB) # SECTION 11.a)
else:
A.update(password) # SECTION 11.b)
i = i >> 1
digestA = A.digest() # SECTION 12.
DP = hash() # SECTION 13.
# SECTION 14.
for _ in range(len(password)):
DP.update(password)
digestDP = DP.digest() # SECTION 15.
P = extend_by_repeat(digestDP, len(password)) # SECTION 16.a), 16.b)
DS = hash() # SECTION 17.
# SECTION 18.
for _ in range(16 + digestA[0]):
DS.update(salt)
digestDS = DS.digest() # SECTION 19.
S = extend_by_repeat(digestDS, len(salt)) # SECTION 20.a), 20.b)
# SECTION 21.
digest_iteration_AC = digestA
for i in range(rounds):
C = hash() # SECTION 21.a)
if i % 2:
C.update(P) # SECTION 21.b)
else:
C.update(digest_iteration_AC) # SECTION 21.c)
if i % 3:
C.update(S) # SECTION 21.d)
if i % 7:
C.update(P) # SECTION 21.e)
if i % 2:
C.update(digest_iteration_AC) # SECTION 21.f)
else:
C.update(P) # SECTION 21.g)
digest_iteration_AC = C.digest() # SECTION 21.h)
shuffled_digest = shuffle_sha512(digest_iteration_AC)
prefix = salt_prefix # SECTION 22.a)
# SECTION 22.b)
if rounds_defined:
prefix += 'rounds={0}$'.format(rounds_in)
return (prefix
+ salt.decode('ascii') # SECTION 22.c)
+ '$' # SECTION 22.d)
+ custom_b64encode(shuffled_digest) # SECTION 22.e)
)
actual = sha512_crypt('password', 'salt1234')
expected = '$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
print(actual)
print(expected)
assert actual == expected

Categories

Resources