Browsing Tag

passwords

Passwords

Authentication of Users and Passwords in Python

January 29, 2013

Before we dive in to the topic, I would like to apologies. Over the past 10 days, I have had multiple matters that require my attention. While I try to allocate some time for everything, this blog has not been on the top of my priorities. This was a mistake, I now realize. I should have anticipated some of the issues and plan ahead accordingly. The opposite is what happened. I cannot say this will not happen again, I can only apologies and try to do better in the future. So let us get started.

The last post I wrote talked about how to password protect your python program. Although this is very neat and sufficient in most cases, what you really need is a method to authenticate users and password. This post will be rather simple and straight to the point. Much of the work it relies on we have done already. Recall at this point we are storing the password as encrypted strings in a file, independent of our python program. Now we just have 2 things we have to do. We will start by recognizing a single user and allow him/her accesses. Then, we will expand the program to allow multiple allowed users accesses. As noted before, we are going to use Python2.7, I strongly encourage referring to the documentation or download the documentation for python2.7 for offline reference.

As we did previously, before we can authenticate any user we have figure out how we want to store the data we are comparing to. You may recall we used a support program to create a file and store the password. Now we will extend the “helper” script to store a user name on a single line, followed by the encrypted password in the next line. This format may be modified at your discretion. For example, you may choose to encrypt both the user name and the password. You may also choose to have all the information as a single line, separated by a vertical line, ‘|’, or a comma, ‘,’. The options are multiple, but the principle is the same. Assuming we follow the first suggested format, here is how the code to store a user name and password will look like:


import sys
import hashlib
import getpass

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: store_user_pass.py <file_name>')

	print '\nUser & Password Storage Program v.01\n'
	
	if raw_input('The file ' + sys.argv[1] + ' will be erased or overwrite if exsting.\nDo you wish to continue (Y/n): ') not in ('Y','y') :
		sys.exit('\nChanges were not recorded\n')
	
	user_name = raw_input('Please Enter a User Name: ')
	password = hashlib.sha224(getpass.getpass('Please Enter a Password: ')).hexdigest()

	try:
		file_conn = open(sys.argv[1],'w')
		file_conn.write(user_name + '\n')
		file_conn.write(password + '\n')
		file_conn.close()
	except:
		sys.exit('There was a problem writing to the file!')

	print '\nPassword safely stored in ' + sys.argv[1] + '\n'		
			
if __name__ == "__main__":
	main(sys.argv[1:])

Note that the changes from our previous version, store a single encrypted password, have not changed much. The main thing we have done is added a user_name variable that gets written to the file. As before, we warn the user from alteration of a file might already exist. Here is an example output of the program:

wpid-userandpasswordstorage-2013-01-21-16-37.png

Here are the content of the file pass_db.txt:


cptdeadbones
99fb2f48c6af4761f904fc85f95eb56190e5d40b1f44ec3a9c1fa319

Now we are ready to see how the other side of this program might look like. Since we know how to verify the password, adding the user name option is not much change. For our application purpose, we will terminate the program if the user name is not known or x password attempts have been made. Here is how the code for this will look like:


import sys
import hashlib
import getpass

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: user_pass.py <file_name>')

	print '\nUser & Password Authentication Program v.01\n'

	try:
		file_conn = open(sys.argv[1])
		user_name = file_conn.readline()[:-1]
		password = file_conn.readline()[:-1]
		file_conn.close()
	except:
		sys.exit('There was a problem reading the file!')
		
	pass_try = 0 
	x = 3
	
	if raw_input('Please Enter User Name: ') != user_name:
		sys.exit('Incorrect User Name, terminating... \n')
	
	while pass_try < x:
		user_input = hashlib.sha224(getpass.getpass('Please Enter Password: ')).hexdigest()
		if user_input != password:
			pass_try += 1
			print 'Incorrect Password, ' + str(x-pass_try) + ' more attemts left\n'
		else:
			pass_try = x+1
			
	if pass_try == x and user_input != password:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'		
			
if __name__ == "__main__":
	main(sys.argv[1:])

Running the code with the file we generated before, pass_db.txt:

wpid-userpassverify-2013-01-21-16-37.png

Like previous programs, the user is prompt for a password 3 times. At each trial the user is notified the number of password attempts reaming. At this point, if you have been following along, you should be able to pice together how this might be extended to multiple users. For our final version we will have 2 python files, one to generate a password file and the other to log the user in. The modification for the storage code needed at this point are minimal, all we need to change is the mode we write to the file. In previous versions we used ‘w’ for write mode. Now we are going to use ‘a’, which is only going to append the new information to the end of the file. If the file is not yet created, the file will be created.You can look users and password storage program.

Last but not least, here is our final version of the authentication module. First the code:


import sys
import hashlib
import getpass

def process_file(file_name):
	
	user_names = []
	passwords = []
	
	try:
		file_conn = open(file_name)
		data = file_conn.readlines()

		for i in range(len(data)): 
			if i%2 == 0:
				user_names.append(data[i][:-1])
			else:
				passwords.append(data[i][:-1])
			
		file_conn.close()
	except:
		sys.exit('There was a problem reading the file!')
		
	return user_names, passwords

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: user_pass.py <file_name>')

	print '\nUser & Password Authentication Program v.01\n'

	user_names, passwords = process_file(sys.argv[1])
		
	pass_try = 0 
	x = 3
	
	user = raw_input('Please Enter User Name: ')
	
	if user not in user_names:
		sys.exit('Unkown User Name, terminating... \n')
		
	while pass_try < x:
		user_input = hashlib.sha224(getpass.getpass('Please Enter Password: ')).hexdigest()
		if user_input != passwords[user_names.index(user)]:
			pass_try += 1
			print 'Incorrect Password, ' + str(x-pass_try) + ' more attemts left\n'
		else:
			pass_try = x+1
			
	if pass_try == x:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'		
			
if __name__ == "__main__":
	main(sys.argv[1:])


So what is different? Now instead of just reading one user name and password, we read more. The information is stored in 2 (2things) lists that have corresponding indexes. So the user name at index 1 has an encrypted password stored at index 1 of the password list. All other operation are the same as any previous example. I do not think there is a need to include an input, it is the same as before.

For a final remark, I realize that the method I discussed in this and the previous post and this one are not very secure or useful outside of an educational exercise. In ‘real world’ applications the information will be stored in a database. There are some software that has already been pre written for user authentication in python. The bottom line is that user authentication is not enough to protect an application. There are several more methods we may or may not cover in the future. For the near time, we will start to look into security algorithms and application.

Passwords

Password Protecting Your Python Application

January 18, 2013

Couple weeks back we talked about how to generate passwords in python. Now, I would like to explore how to password protect your application. We will be using Python again, only this time I will upgrade to Python2.7 due to popular demand. You can reference to Python2.7 the documentation or download Python2.7 documentation.

There are many situations in which you would like to password protect the application. It could be just a simple application you do not want anyone else to run, or it could be an application that stores sensitive data. The two things you need to keep in mind is that authentication is independent of the application and that we are discussing application authentication. That is, the ideas may apply to web, mobile & other applications, however, we are going to limit this discussion to python application.

Lost You Password?<a href="http://c9d568r8ox3aii95ujuky1vcxo.hop.clickbank.net/" target="_top">Click Here!</a>

Let us start by assuming there is an application we wish to secure. For demonstration purpose, the application will simply print out:

User is logged in!

Otherwise an appropriate error message will be displayed. We can agree that the print statement can be replaced with a function call to start an application. We are going to start with the simplest case. We have a string password that is stored in a variable. We prompt the user for a password. If the user input does not match the stored password, we terminate the application without letting the user log in. Here is what that would look like in code:


import sys

def main():

	print '\nPassword Request Program v.01\n'

	password = 'abcd'
	user_input = raw_input('Please Enter Password: ')

	if user_input != password:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'

if __name__ == &quot;__main__&quot;:
	main()

And the output of the program in both cases:

password auth 1_1

password auth 1_2

You can see that the first time the user entered ‘password’ for the password. The program recognizes an incorrect password and is terminated. The second time the user entered the correct password ‘abcd’ and the user was successfully logged in. For a simple application, this might be enough. However, we are going to take this idea much further. To start, let us add the ability for the user to try to enter a password x amount of times before the program is terminated. For now, let us assume x is 3. You might change the value of x to any number you wish. Our modifed program might look like this:


import sys

def main():

	print '\nPassword Request Program v.02\n'

	password = 'abcd'
	pass_try = 0
	x = 3

	while pass_try &lt; x:
		user_input = raw_input('Please Enter Password: ')
		if user_input != password:
			pass_try += 1
			print 'Incorrect Password, ' + str(x-pass_try) + ' more attempts left\n'
		else:
			pass_try = x + 1

	if pass_try == x and user_input != password:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'

if __name__ == &quot;__main__&quot;:
	main()

Sample output:

password auth 2_2_2

password auth 2_2_1

If you examine the code you might notice a few different things. We have a while-loop that runs for x amount of times. This might be replaced with a simple for-loop, but keep in mind that there is no guarantee that the user will need any incorrect attempts. In addition, if you do use a for loop, you might need to use a break statement, which is not a good programming habit. You might also notice that that the program notifies the user how many attempts he or she has left. This is not required, but as a user it is nice to know.

As you examine the code, you will soon realize that storing the password in the code as a string is not the best practice. Let us move the password into a file. This way we can separate the password from the program. The path for the file will be given as a command line argument. The file can by anywhere in the file system, including on a USB drive. Without it, the program will not run and terminate immediately. For this example, we will store the password in a plain txt file called pass_file1.txt. Here is the content of the text file:


abcd

Here is our new version, using the file to store the password:


import sys

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: pass_auth3.py &lt;file_name&gt;')

	print '\nPassword Request Program v.03\n'

	try:
		file_conn = open(sys.argv[1])
		password = file_conn.readline()[:-1]
		file_conn.close()
	except:
		sys.exit('There was a problem reading the file!')

	pass_try = 0
	x = 3

	while pass_try &lt; x:
		user_input = raw_input('Please Enter Password: ')
		if user_input != password:
			pass_try += 1
			print 'Incorrect Password, ' + str(x-pass_try) + ' more attempts left\n'
		else:
			pass_try = 4

	if pass_try == x and user_input != password:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'

if __name__ == &quot;__main__&quot;:
	main(sys.argv[1:])

And here is some sample output. Notice that the first try is without giving the program a path to a file.

password auth 3_2_1
password auth 3_2_2
password auth 3_2_3

Take a closer look at the code. You will notice that there is more than one way the program can might terminate. If a file is not provided the program will terminate immediately. If there are any issues reading the file the program will terminate. Finally, if the password is incorrect more than x times the program will terminate. When reading from the file we use the readline() method. This will read an entire line from the file, including the newline character ‘\n’. This is why there is an added [:-1] to trim the string to not include the newline character.

So far we have seen how to ask for a simple password. However, this is far from a real-world application strength. The problem is that the password is stored as a plain text file. This means that if anyone was to open it, they will know your password immediately. As a good programmer, you do not want a client to find out their secure passwords are stored in plain text. Much less a user finding that out. Or worse. To solve this problem we will introduce 2 (2things) new ideas. First a method to avoid seeing the characters as the user types. Second, we will encrypt the password we store in the file using one way encryption.

In order to hide the password while the user is typing, we will use a python standard library named getpass. The library is quite small, but provides exactly what the name suggests and nothing else. Here is a simple example of how the library works:

wpid-getpassexample-2013-01-17-20-47.png

Basically, getpass.getpass() is equivalent to using raw_input(), but hides the typed characters. I think it is rather straight forward why you should use this library when asking a user for a password. Moving on to the second thing, we need a way to encrypt our password. Furthermore, we want our password encrypted using a one way encryption method. This means that once we encrypt the data, there is no simple function to retrieve the data. Python has a multiple ways to achieve this using standard library functions. We will use a built-in library called hashlib that provides many encryption methods. I choose to follow on of the examples and use sha224 with conversion to hex. Here is an example of using sha224:

wpid-shaexample-2013-01-17-20-47.png

You can see that the encrypted string has nothing to do with the string ‘password’. So how are we going to use one way encryption? Simple, we are going to store the original encrypted password in the file. Then when the user enters a password we will encrypt the user input exactly the same way and compare the encrypted string from the file. If we do not use the same encryption algorithm, this method will not work. You may change the encryption algorithm to what every method you like. Since we need to encrypt the passwords, we will need a helper program to store the password before we modify the authentication program. Here is an example program to store the an encrypted password:


import sys
import hashlib
import getpass

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: store_pass.py &lt;file_name&gt;')

	print '\nPassword Storage Program v.01\n'

	if raw_input('The file ' + sys.argv[1] + ' will be erased or overwrite if existing.\nDo you wish to continue (Y/n): ') != 'Y' :
		sys.exit('\nChanges were not recorded\n')

	password = hashlib.sha224(getpass.getpass('Please Enter a Password: ')).hexdigest()

	try:
		file_conn = open(sys.argv[1],'w')
		file_conn.write(password + '\n')
		file_conn.close()
	except:
		sys.exit('There was a problem writing to the file!')

	print '\nPassword safely stored in ' + sys.argv[1] + '\n'

if __name__ == &quot;__main__&quot;:
	main(sys.argv[1:])

Here is an example output for this program:

wpid-storepass1-2013-01-17-20-47.png

The program is fairly simple. First we verify that the user acknowledges that if the file exists already it will be erased. There are other ways around this, but this is one of the simple solutions. You do not want to assume the user entered the right file name the first time. If you were to use a file name that already exists, the file will be permanently altered. Since we opened the file in write mode, we will erase any information already there. This is why you should double check that the user entered the correct file name. Of course, you do not have to do it and you may erase the associated if statement.

As a last note, we do not store the plain value of the password in a variable. Instead it is transferred directly to the encryption method. This offers some extra security to you program. Finally, we write the information to the file and terminate the program. If we were to look at the content of pass_file2.txt we will see something like this:


a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601

Now we are ready for our final version of password authentication, using the encrypted password file. Here is the code for it:


import sys
import hashlib
import getpass

def main(argv):

	if len(argv) != 1:
		sys.exit('Usage: pass_auth3.py &lt;file_name&gt;')

	print '\nPassword Request Program v.04\n'

	try:
		file_conn = open(sys.argv[1])
		password = file_conn.readline()[:-1]
		file_conn.close()
	except:
		sys.exit('There was a problem reading the file!')

	pass_try = 0
	x = 3

	while pass_try &lt; x:
		user_input = hashlib.sha224(getpass.getpass('Please Enter Password: ')).hexdigest()
		if user_input != password:
			pass_try += 1
			print 'Incorrect Password, ' + str(x-pass_try) + ' more attempts left\n'
		else:
			pass_try = 4

	if pass_try == x and user_input != password:
		sys.exit('Incorrect Password, terminating... \n')

	print 'User is logged in!\n'

if __name__ == &quot;__main__&quot;:
	main(sys.argv[1:])

Notice that not much has changed. What we have added is applying the same encryption method we did to the file, to the user input. Here is how the program looks like when it runs:

password auth 4_1

password auth 4_2

We have explored adding a password security to your python program. If you really want to use it, you will need to conceal your code. One way to conceal your code is to compile code to a pyc file. This is just one way you might do this. There are other methods you could explore to create executable from p a py file. We will not explore them within this post. For the moment, I will leave you with a pyc file and a file containing an encrypted password. The application will have a unique output. Can you make the application run?

pyc riddle file
passwod file

Cool Stuff

Generating and Checking Passwords in Python

January 2, 2013

During my typical day I find myself logging in to about a dozen or more services. Good password habits tell us to keep the passwords different for each service or username. Not only that, most websites require you to use special characters, upper and lower case, keep changing the password and my top 'favorite', replace your password every X amount of time. As computers are getting faster, cracking passwords is becoming easier. To compensate, we are told to use longer passwords, great. So in theory, we all have 32-64 character passwords that are supper strong and our privacy is kept safe. In reality, we have maybe a handful of passwords and the forgot password link (in hope that we used an email we actually have). So in a time where we have all our information online and kept by passwords we hope not to be cracked, so what can we do with this 'too many passwords' problem?

The answer to this question is short and simple, we do what we can. In this post we will look at how to randomly generate passwords and how to check their security level to some degree. So let us get to it. Generating passwords is something that is rather straight forward. To sum it all up, randomly choose X characters from a given set. We will look at a few ways to generate passwords starting from a simple one. All of them follow that same basic rule.


import random
import sys

def main(argv):

	if (len(sys.argv) != 2):
		sys.exit('Usage: simple_pass.py <password_length>')
    
	password = ''
	for i in range(int(argv[0])):
		password += chr(random.randint(33,126))
	
	print 'You new password is: ' + password

if __name__ == "__main__":
	main(sys.argv[1:])

Using the python random module and passing in via command line the length of the password, we are able to randomly generate a unique password. The passwords are built from all printable ASCII characters randomly chosen. Later we will come back to this example to test a checking password strength program. Here are some example runs of this program.

wpid-pythongenrandompassword1-2013-01-2-02-24.png

This is a nice and simple script anyone can write and by all means use and distribute. It might be a quick hack, but still is not enough to get to be a true generator. Before we move on to another, more sophisticated password generator, lets actually look at a really unique generator using python's lambda.


import random
import string

pass_gen = lambda length, ascii =  string.ascii_letters + string.digits + string.punctuation: "".join([list(set(ascii))[random.randint(0,len(list(set(ascii)))-1)] for i in range(length)])

To use this lambda simply call it with the length required, like so:

wpid-pythongeneratepasswordex2.2.1-2013-01-2-02-24.png

Most password requirements today specify the number of special characters, uppercase, lowercase and numbers require in a password. Using the python string library, we can use string attributes to choose a number of specific characters from each set. Now we can modify our password generator to accept the number of uppercase, lowercase, digits and special charcters. The new code and example output will look like this:


import random
import sys
import string

def main(argv):

	if (len(sys.argv) != 5):
		sys.exit('Usage: simple_pass.py <upper_case> <lower_case> <digit> <special_characters>')
    
	password = ''
	
	for i in range(len(argv)):
		for j in range(int(argv[i])):
			if i == 0:
				password += string.uppercase[random.randint(0,len(string.uppercase)-1)]
			elif i == 1:
				password += string.lowercase[random.randint(0,len(string.lowercase)-1)]
			elif i == 2:
				password += string.digits[random.randint(0,len(string.digits)-1)]
			elif i == 3:
				password += string.punctuation[random.randint(0,len(string.punctuation)-1)]
	
	print 'You new password is: ' + ''.join(random.sample(password,len(password)))

if __name__ == "__main__":
	main(sys.argv[1:])


wpid-pythongeneratepasswordex3-2013-01-2-02-24.png

So at this point we can generate randomize and customize passwords. Let us now move to checking a password strength algorithm and check what kind of passwords we are generating. We will start by using a modified version of a password checker found on Password Advisor. I had to modify the code to get it to run and to create some output. Take a look.


import re

def CheckPassword(password):
    strength = ['Blank','Very Weak','Weak','Medium','Strong','Very Strong']
    score = 1

    if len(password) < 1:
        return strength[0]
    if len(password) < 4:
        return strength[1]

    if len(password) >=8:
        score = score + 1
    if len(password) >=10:
        score = score + 1
    
    if re.search('\d+',password):
        score = score + 1
    if re.search('[a-z]',password) and re.search('[A-Z]',password):
        score = score + 1
    if re.search('.,[,!,@,#,$,%,^,&,*,(,),_,~,-,]',password):
        score = score + 1

    return strength[score]
    
def main():
	
		
	user_input = raw_input("Check: ")

	while(user_input != 'quit'):
		print CheckPassword(user_input)
		user_input = raw_input("Check: ")

if __name__ == "__main__":
	main()


wpid-pythonpasswordstrengthchecker2-2013-01-2-02-24.png

The program uses length and python's regular expressions to determine a score for the password. This is a fairly straight forward calculation. A password longer than 8 characters is awarded 1 point, longer than 10 is awarded an additional point. Then, for each character from a character set the password is awarded another point. The points corresponding to an index on the strength list and an appropriate rating is determined. Let us see how our three password generators from before hold up to this checker standards. (The code has been slightly modified for testing).


import passwordadvisor
import random
import string
import re
import sys 

def ex1(num):

	password = ''
	for i in range(int(num)):
		password += chr(random.randint(33,126))
	
	return password
	
ex2 = lambda length, ascii =  string.ascii_letters + string.digits + string.punctuation: "".join([list(set(ascii))[random.randint(0,len(list(set(ascii)))-1)] for i in range(length)])

def ex3(argv):
    
	password = ''
	
	for i in range(len(argv)):
		for j in range(int(argv[i])):
			if i == 0:
				password += string.uppercase[random.randint(0,len(string.uppercase)-1)]
			elif i == 1:
				password += string.lowercase[random.randint(0,len(string.lowercase)-1)]
			elif i == 2:
				password += string.digits[random.randint(0,len(string.digits)-1)]
			elif i == 3:
				password += string.punctuation[random.randint(0,len(string.punctuation)-1)]
	
	return ''.join(random.sample(password,len(password)))
	
def checker(argv):

	example_1 = ex1(argv[1])
	print example_1 + ' ' + passwordadvisor.CheckPassword(example_1)
	
	example_2 = ex2(int(argv[2]))
	print example_2 + ' ' + passwordadvisor.CheckPassword(example_2)
	
	example_3 = ex3([argv[3],argv[4],argv[5],argv[6]])
	print example_3 + ' ' + passwordadvisor.CheckPassword(example_3)
		
def main(argv):
	if (len(sys.argv) != 7):
		sys.exit('Usage: ex4.py <length1> <length2> <upper_case> <lower_case> <digit> <special_characters>')
		
	checker(sys.argv)

if __name__ == "__main__":
	main(sys.argv[1:])

python exp 3

Test runs have shown that any password of length 8 is considered medium to strong by this measures. Notably the third generator has generated the strongest password at all test runs when 2 characters were chosen from each set. I have tested out the passwords generated using the website appropriately named HowSecureIsMyPassword. I do not advise nor condemn you trying to type your real password, but I have checked our generated passwords using this site. It seems that by their standards any 8 characters long password will take anywhere for a day to 20 days for a desktop PC to crack. For a 16 characters long password it seems that it will take 412 trillion years. So we are still safe on that side. It was shocking to know that some other sites that rank passwords, like ThePasswordMeter ranked any 8 character password we generated as high while HowSecureIsMyPassword claims it will take a day to crack the same password. However, 16 character long passwords were considered strong at both sites.

wpid-howsecure1.1-2013-01-2-02-24.png

wpid-thepassmeter-2013-01-2-02-24.png

wpid-howsecure1.2-2013-01-2-02-24.png

wpid-thepassmeter2-2013-01-2-02-24.png

Let us look at least at one more measure of password strength called bit strength, used to measure the strength of random generated passwords. it follows a formula where each character contributes an amount of bits calculated by the following formula:

 log_{2}(N)

The results is multiplied by the number of characters and a final bit strength is calculated. The threshold recommend, according to Wikipedia, for most secure systems is 80-bits. Let us look at how this will look in code and how our generated passwords measure up to this threshold. The code is very similar to the previous example, only replacing the checker function. (Download code for password generator and checker)


def bit_strength(password):
	return str(math.floor(len(password)*math.log(94,2)))


python exp 4

Since the character set we have include 94 possible characters in all generators, we have a constant log value (~6.55). This means that no matter what password we generate, even 88888888 will have the same ‘bit strength’ as ‘1.U*1!lh’. We can all recognize that the latter one will be much harder to crack than the first one. This is because the formula applies for randomly generated passwords. I will let the statistician among us calculate the odds of generating 88888888 out of 8 characters with 94 possible values for each character. I will "guesstimate" that it is very close to 0. We can draw a graph following this information to determine the length threshold required for a randomly generated password to pass the bit strength threshold.

wpid-lengthofpasswordvstrength2-2013-01-2-02-24.png

You will notice that any password above 15 characters is over 100 on the bit strength index. This means that it will comply with the secure password guideline as indicated on Wikipedia. It also means that if you can remember a randomly generated password, you will need less than 32 characters to secure your password. Keep in mind that this is limited to random generated password and not human created passwords.

So what can you do? In the mean time keep remembering that regardless of the source of password, the length is a directly proportional to the password strength according to any calculation. At this point I have no real solution to the ‘too many passwords’ problem, but I do have hope. I will continue with my work on the matter and post any changes I might have. Keep your passwords secure and safe.