I've written a little bottle web app to run on my raspberry pi and control a boiler. There is a log in page and a create new user page. When I create a new user it generates a salt and uses sha512 to hash the password and both are stored in the database. When a user logs in it matches the userid's and gets the salt and password hash from the database and hashes the presented password with the salt from the database but always creates a different hash so the log in fails. I'm sure its something stupid but I just can't sort it.
This is the code that does the password hashing/checking/salt
def get_password(userid):
userid = userid.upper()
logging.debug('get password for %s' % userid)
conn_string = prop('database')
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
sql = """
select password, salt from users where userid = %(userid)s
"""
cursor.execute(sql, {'userid':userid})
row = cursor.fetchone()
if row is not None:
dbpassword = row[0]
dbsalt = str(row[1])
logging.debug('db password hash %s' % dbpassword)
logging.debug('db password salt %s' % dbsalt)
return dbpassword, dbsalt
else:
logging.debug('No details found for user')
return None, None
def check_password(password, userid):
logging.debug('username/password to check is %s/%s' % (password, userid))
dbpassword, dbsalt = get_password(userid)
if dbpassword is not None:
test = hash_password(password, dbsalt)
logging.debug('test password hash %s' % test)
if test == dbpassword:
logging.debug('password correct')
return True
else:
logging.debug('password incorrect')
return False
else:
return False
def hash_password(password, salt):
if salt == '0':
logging.debug('hashing password')
logging.debug('generate salt')
salt = uuid.uuid4().hex
logging.debug('salt = %s' % salt)
hashed_password = crypt(password, salt)
logging.debug('hashed password = %s' % hashed_password)
return salt, hashed_password
else:
logging.debug('hash password for compare')
hashed_password = crypt(password, salt)
logging.debug('hashed password = %s' % hashed_password)
return hashed_password
def crypt(password, salt):
hashed_password = hashlib.sha512(password.encode(encoding='utf_8') + salt.encode(encoding='utf_8')).hexdigest()
return hashed_password
and this is the bit that gets the details from the login page:
def main():
try:
rqstSession = request.get_cookie('pysessionid', secret=prop('cookieSecret'))
username = request.forms.get('username').upper()
password = request.forms.get('password')
if request.forms.get('override','').strip() is '':
if check_password(password, username) is True:
set_session(rqstSession)
return template('main')
elif check_session(rqstSession) is True:
if request.forms.get('override','').strip():
logging.debug('override')
set_override()
return template('main')
else:
return template('login')
except Exception as e:
logging.debug('exception in main: %s' % e)
return '<p>Error</p>'
and this gets the details from the new user page:
def new_user():
try:
rqstSession = request.get_cookie('pysessionid', secret=prop('cookieSecret'))
if check_session(rqstSession) is True:
if request.forms.get('save','').strip():
userid = request.forms.get('userid', '').upper()
password = request.forms.get('password','')
confpassword = request.forms.get('confpassword','')
salt = '0'
if password is not '' and password == confpassword and userid is not '':
salt, hashed_password = hash_password(userid, salt)
conn_string = prop('database')
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
sql = """
insert into users (id_usrr, userid, password, salt) values (nextval('users_id_usrr_seq'), %(userid)s, %(password)s, %(salt)s)
"""
cursor.execute(sql, {'userid':userid, 'password':hashed_password, 'salt':salt})
conn.commit()
cursor.close()
else:
return template('newuser')
else:
return template('newuser')
else:
pysessionid = ''
response.set_cookie('pysessionid', pysessionid, secret=prop('cookieSecret'), Expires='Thu, 01-Jan-1970 00:00:10 GMT', httponly=True)
return template('main')
except Exception as e:
logging.debug(e)
return '<p>Error</p>'
I tried removing the salt and it didn't help so I don't think its anything to do with that but I'm willing to try anything after bang my head against a wall for the last 2 hours
Thanks
Adam