Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agnostic hash #15

Merged
merged 5 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
usrlist
__pycache__/usrcheck.cpython-310.pyc
# Ignore the whole cache
__pycache__/
22 changes: 13 additions & 9 deletions backendtest.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import usrcheck
import hashlib
import hash
def test_auth():
usr_list=[['testusr',hashlib.sha256(str('testPSWD'+'1QgF35ws').encode()).hexdigest(),'1QgF35ws']]
usrcheck.save_users(usr_list,True)
assert usrcheck.load_users() == usr_list, "Userlist loading failed"
assert usrcheck.usr_check('testusr', 'testPSWD',usr_list) == (True,True), "User check failed"
#Wrong username
assert usrcheck.usr_check('wrongusr', 'testPSWD',usr_list) == (False,False), "User check failed"
#Wrong password
assert usrcheck.usr_check('testusr', 'wrongPSWD',usr_list) == (True,False), "User check failed"
# Updated test to support new implementation
for hash_method in hash.SUPPORTED_HASHES:
hasher = hash.Hasher(hash_method, ('testPSWD' + '1QgF35ws').encode())
usr_list = [['testusr', hasher.hexdigest(), '1QgF35ws']]
hasher.clear_hasher()
usrcheck.save_users(usr_list, True)
assert usrcheck.load_users() == usr_list, "UserList loading failed"
assert usrcheck.usr_check('testusr', 'testPSWD', usr_list, test_hasher=hasher) == (True,True), "User check failed"
#Wrong username
assert usrcheck.usr_check('wrongusr', 'testPSWD', usr_list, test_hasher=hasher) == (False,False), "User check failed"
#Wrong password
assert usrcheck.usr_check('testusr', 'wrongPSWD', usr_list, test_hasher=hasher) == (True,False), "User check failed"
test_auth()
28 changes: 28 additions & 0 deletions hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import hashlib

SUPPORTED_HASHES = hashlib.algorithms_available

class Hasher():
def __init__(self, hash_name: str, initial_data: bytes = b'', **kwargs):
if not (hash_name in SUPPORTED_HASHES):
raise ValueError(f"{hash_name} is not a supported hashing algorithm")
self.__hash_implementation: hashlib._Hash = hashlib.new(hash_name, initial_data, **kwargs)
self.__kwargs = kwargs

# Convenient but wont show up in lsp, might have to define each method later
def __getattr__(self, name):
return getattr(self.__hash_implementation, name)

def hexdigest(self, shake_output_size: int=None) -> bytes:
if self.__hash_implementation.name in ('shake_128', 'shake_256'):
if shake_output_size:
return self.__hash_implementation.hexdigest(shake_output_size)
# Good default output sizes for shake
elif self.__hash_implementation.name == 'shake_128':
return self.__hash_implementation.hexdigest(32)
elif self.__hash_implementation.name == 'shake_256':
return self.__hash_implementation.hexdigest(64)
return self.__hash_implementation.hexdigest()

def clear_hasher(self) -> None:
self.__hash_implementation = hashlib.new(self.__hash_implementation.name, b'', **self.__kwargs)
57 changes: 46 additions & 11 deletions usrcheck.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import hash

# TODO: Encapsulate this later
hasher = None

def configRead():
import configparser
config = configparser.ConfigParser()
Expand All @@ -8,11 +13,16 @@ def configRead():
except KeyError:
quiet = False
try:
alg = config['Config']['alg']
alg = str(quiet).lower()
alg = config['Config']['alg'].lower()
# alg = str(quiet).lower() Not really sure the purpose of this line
# Not the most elegant but trying to hit the KeyError on unsupported hash algs
if not (alg in hash.SUPPORTED_HASHES):
raise KeyError
except KeyError:
print("ERROR: Algorithm not defined. Reverting to SHA256")
alg = 'sha256'
global hasher
hasher = hash.Hasher(alg)
try:
saltSize = config['Salt']['saltSize']
saltSize = int(saltSize)
Expand All @@ -29,7 +39,6 @@ def salter(pswd,saltsize):
return pswd+salt,salt

def init_usrs(nUsr, saltSize):
import hashlib
usrlist=[]
for index in range(nUsr):
usrname=''
Expand All @@ -39,7 +48,10 @@ def init_usrs(nUsr, saltSize):
while pswd=='':
pswd = input("Enter password: ")
pswd,salt = salter(pswd,saltSize)
pswd = hashlib.sha256(pswd.encode()).hexdigest()
hasher.update(pswd.encode())
pswd = hasher.hexdigest()
# We have to clear the hasher every time with the new implementation, later we could define this behaviour automatically
hasher.clear_hasher()
usrlist.append([])
usrlist[index].append(usrname)
usrlist[index].append(pswd)
Expand Down Expand Up @@ -78,15 +90,35 @@ def save_users(usrlist,overWrite):
saveFile.write('')
saveFile.close()

def usr_check(usrn,pswd,usrlist):
import hashlib
def usr_check(usrn,pswd,usrlist, test_hasher: hash.Hasher=None):
if test_hasher:
hasher = test_hasher
# TODO:
# Supporting different hashes means we have to figure out what hash was used for the usrlist
# This basic solution simply reads what hash was specified in the config file.
# The config file will need additional information, and this logic will have to be changed, if variable
# output for shake is allowed.
else:
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
try:
alg = config['Config']['alg'].lower()
if not (alg in hash.SUPPORTED_HASHES):
raise KeyError
except KeyError:
print("No algorithm specified to read usrlist or unsuporrted algorithm\nDefaulting to sha256")
alg = 'sha256'
hasher = hash.Hasher(alg)
index=0
Ufound=False
Pfound=False
while Ufound==False and index<len(usrlist):
if usrlist[index][0]==usrn:
Ufound=True
pswd=hashlib.sha256(str(pswd+str(usrlist[index][2])).encode()).hexdigest()
hasher.update(str(pswd+str(usrlist[index][2])).encode())
pswd = hasher.hexdigest()
hasher.clear_hasher()
if usrlist[index][1]==pswd:
Pfound=True
break
Expand Down Expand Up @@ -118,11 +150,14 @@ def login_init(usrname,pswd,overWrite,quiet,saltSize):
print("Userfile does not exist! Execute with overWrite set to 'True'")
sys.exit()
elif overWrite==True:
if input("Do you want to overwrite the existing user list[y/N]? ").upper()=='Y':
newFile=True
else:
newFile=False
# Bug fix for when no usrlist exists but the user asks not to overwrite user list
newFile = True
if os.path.isfile("usrlist") and (input("Do you want to overwrite the existing user list [Y/N]? ").upper() == 'N'):
newFile = False
while True:
# TODO:
# Seems to me redundant to ask if they want to clear the database when "overwriting" the existing database does
# the same thing.
nUsr=input("Enter the number of users to initialize ('0' Clears the database): ")
try:
nUsr=int(nUsr)
Expand Down
Loading