Question

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

Was it helpful?

Solution

I don't know a lot about security but i think that can solve your problem

>>> # import the hash algorithm
>>> from passlib.hash import sha256_crypt

>>> # generate new salt, and hash a password
>>> hash = sha256_crypt.encrypt("toomanysecrets")
>>> hash
'$5$rounds=80000$zvpXD3gCkrt7tw.1$QqeTSolNHEfgryc5oMgiq1o8qCEAcmye3FoMSuvgToC'

>>> # verifying the password
>>> sha256_crypt.verify("toomanysecrets", hash)
True
>>> sha256_crypt.verify("joshua", hash)
False

so something like:

if sha256_crypt.verify("given_pass", db_hash):
    print("you are now logged in")

passlib

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top