Tags

, , , , , ,

Probably everyone’s seen a program that works something along the lines of:

read UserInput
if UserInput = 'password'
print 'Login Success'
else
print 'Password Incorrect'

The flaw with this method should be obvious: someone could either read the source code or reverse engineer the program to determine the password. To get around this, UNIX systems use another method that involves storing password hashes: when a user enters a password, it’s hashed and stored in a file, or its hash is compared with the values already in that file.
This method is intractable – that is, nobody should be able to determine the password from its digest, since MD5/SHA256 are one-way algorithms. Entering the hash value in the password screen also shouldn’t work, as that value will also be hashed to generate an entirely different digest.

Hashing in Python
Let’s start with the basics, with a simple Python script that generates a SHA256 hash from an input string, using the sha256() function from hashlib:

import os
import hashlib

#Get txtPassword
txtPassword = raw_input("Enter password: ")

#Print the hashed password
print hashlib.sha256(txtPassword).hexdigest()

HashString

Having written a program that hashes user text, the next stage is a simple matter of adding code that writes the output to a file:

import os
import hashlib

#Load password file for appending
f = open('Passwords.txt', 'a')

#Get password
txtPassword = raw_input("Enter password: ")

#Hash newPassword and write to file
newPassword = hashlib.sha256(txtPassword).hexdigest()
f.write(newPassword)

After running the program several times, there should now be a list of digests in Passwords.txt.

password-file

Checking a Password
What turned out to be exceedingly tricky was getting it to work in reverse, with the program again hashing an input string to find a matching value in Passwords.txt. Since I couldn’t get this to work with a conditional branching statement, I resorted to printing ‘Login Fail’ by default and inserting exit() to terminate the program before that point if there’s a match. Probably not a bad thing, security-wise.

import os, sys
import hashlib
import string
import re

#Use hash value of user input as the search term
txtPassword = raw_input("Enter password: ")
searchKey = hashlib.sha256(txtPassword).hexdigest()

#Open the password file
lines = open("Passwords.txt", "r" ).readlines()

#Search the file for matching hash value
for line in lines:
if re.search(searchKey, line ):
print "Login Success"
exit()
print "Login Fail"

A PythonCard Login Screen
Of course, this wasn’t good enough for me. I wanted to apply this as a PythonCard GUI (which I’ll probably cover in my next post). It works a little differently this time, as the program is event driven.
Installing PythonCard gives us a couple of tools: resourceEditor GUI designer, and the codeEditor IDE. The resourceEditor is used for creating the interface itself stuff, while the handlers and back-end code are added to the Python script manually in codeEditor, replacing variables with component names.

PythonCard-Hash

When sorting out the Python script (after creating the GUI), the first step is to import the Python modules used in the earlier programs:

from PythonCard import dialog, model
import os, sys
import hashlib
import string
import re

The handler for the ‘Hash’ button does exactly the same thing as the first script, but I/O is done the same way as with VB.NET:

#The hash button
def on_cmdCancel_mouseClick(self, event):
self.components.txtHash.text = hashlib.sha256(self.components.txtPassword.text).hexdigest()

Creating the handler for the checking (‘Login’) button was much easier than I expected, and was a matter of renaming the variables:

#The login button
def on_cmdLogin_mouseClick(self, event):
searchKey = hashlib.sha256(self.components.txtPassword.text).hexdigest()
#Buffer the password file
lines = open("Passwords.txt", "r" ).readlines()

#Search lines in password file for a match
for line in lines:
if re.search(searchKey, line ):
dialog.alertDialog(self, 'Login Success')

And as a finishing touch, another function to update the password file:

#Password set button
def on_cmdSetPassword_mouseClick(self, event):
f = open('Passwords.txt', 'a')
newPassword = hashlib.sha256(self.components.txtPassword.text).hexdigest()
f.write(newPassword)

dialog.alertDialog(self, 'Password Set')

I honestly didn’t expect the program to work, but it did. Go me! The files have been uploaded to my SourceForge page for y’all play around with.

PythonCard-LoginSuccess

PythonCard-PasswordSet

Advertisements