django s standard crypto functions and utilities algorithm is not supported by hashlib pass def saltedhmackeysalt value secretnone algorithmsha1 if secret is none secret settings secretkey keysalt forcebyteskeysalt secret forcebytessecret try hasher getattrhashlib algorithm except attributeerror as e raise invalidalgorithm r is not an algorithm accepted by the hashlib module algorithm from e we need to generate a derived key from our base key we can do this by passing the keysalt and our base key through a pseudorandom function key hasherkeysalt secret digest if lenkeysalt secret block size of the hash algorithm the above line is redundant and could be replaced by key keysalt secret since the hmac module does the same thing for keys longer than the block size however we need to ensure that we always do this return hmac newkey msgforcebytesvalue digestmodhasher randomstringchars abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789 def getrandomstringlength allowedcharsrandomstringchars return joinsecrets choiceallowedchars for i in rangelength def constanttimecompareval1 val2 return the hash of password using pbkdf2 if digest is none digest hashlib sha256 dklen dklen or none password forcebytespassword salt forcebytessalt return hashlib pbkdf2hmacdigest name password salt iterations dklen algorithm is not supported by hashlib return the hmac of value using a key generated from key_salt and a secret which defaults to settings secret_key default algorithm is sha1 but any algorithm name supported by hashlib can be passed a different key_salt should be passed in for every application of hmac we need to generate a derived key from our base key we can do this by passing the key_salt and our base key through a pseudo random function if len key_salt secret block size of the hash algorithm the above line is redundant and could be replaced by key key_salt secret since the hmac module does the same thing for keys longer than the block size however we need to ensure that we always do this return a securely generated random string the bit length of the returned value can be calculated with the formula log_2 len allowed_chars length for example with default allowed_chars 26 26 10 this gives length 12 bit length 71 bits length 22 bit length 131 bits return true if the two strings are equal false otherwise return the hash of password using pbkdf2
import hashlib
import hmac
import secrets

from django.conf import settings
from django.utils.encoding import force_bytes


class InvalidAlgorithm(ValueError):
    

    pass


def salted_hmac(key_salt, value, secret=None, *, algorithm="sha1"):
    
    if secret is None:
        secret = settings.SECRET_KEY

    key_salt = force_bytes(key_salt)
    secret = force_bytes(secret)
    try:
        hasher = getattr(hashlib, algorithm)
    except AttributeError as e:
        raise InvalidAlgorithm(
            "%r is not an algorithm accepted by the hashlib module." % algorithm
        ) from e
    
    
    key = hasher(key_salt + secret).digest()
    
    
    
    
    return hmac.new(key, msg=force_bytes(value), digestmod=hasher)


RANDOM_STRING_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"


def get_random_string(length, allowed_chars=RANDOM_STRING_CHARS):
    
    return "".join(secrets.choice(allowed_chars) for i in range(length))


def constant_time_compare(val1, val2):
    
    return secrets.compare_digest(force_bytes(val1), force_bytes(val2))


def pbkdf2(password, salt, iterations, dklen=0, digest=None):
    
    if digest is None:
        digest = hashlib.sha256
    dklen = dklen or None
    password = force_bytes(password)
    salt = force_bytes(salt)
    return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)