Password Protecting Your Python Application

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

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.