def encode(self, password, salt): argon2 = self._load_library() data = argon2.low_level.hash_secret( force_bytes(password), force_bytes(salt), time_cost=self.time_cost, memory_cost=self.memory_cost, parallelism=self.parallelism, hash_len=argon2.DEFAULT_HASH_LENGTH, type=argon2.low_level.Type.I, ) return self.algorithm + data.decode('ascii')
def verify(self, password, encoded): argon2 = self._load_library() algorithm, rest = encoded.split('$', 1) assert algorithm == self.algorithm try: return argon2.low_level.verify_secret( force_bytes('$' + rest), force_bytes(password), type=argon2.low_level.Type.I, ) except argon2.exceptions.VerificationError: return False
def encode(self, password, salt): bcrypt = self._load_library() # Hash the password prior to using bcrypt to prevent password # truncation as described in #20138. if self.digest is not None: # Use binascii.hexlify() because a hex encoded bytestring is # Unicode on Python 3. password = binascii.hexlify(self.digest(force_bytes(password)).digest()) else: password = force_bytes(password) data = bcrypt.hashpw(password, salt) return "%s$%s" % (self.algorithm, force_text(data))
def pbkdf2(password, salt, iterations, dklen=0, digest=None): """ Implements PBKDF2 as defined in RFC 2898, section 5.2 HMAC+SHA256 is used as the default pseudo random function. As of 2014, 100,000 iterations was the recommended default which took 100ms on a 2.7Ghz Intel i7 with an optimized implementation. This is probably the bare minimum for security given 1000 iterations was recommended in 2001. This code is very well optimized for CPython and is about five times slower than OpenSSL's implementation. Look in orun.contrib.auth.hashers for the present default, it is lower than the recommended 100,000 because of the performance difference between this and an optimized implementation. """ assert iterations > 0 if not digest: digest = hashlib.sha256 password = force_bytes(password) salt = force_bytes(salt) hlen = digest().digest_size if not dklen: dklen = hlen if dklen > (2 ** 32 - 1) * hlen: raise OverflowError('dklen too big') l = -(-dklen // hlen) r = dklen - (l - 1) * hlen hex_format_string = "%%0%ix" % (hlen * 2) inner, outer = digest(), digest() if len(password) > inner.block_size: password = digest(password).digest() password += b'\x00' * (inner.block_size - len(password)) inner.update(password.translate(hmac.trans_36)) outer.update(password.translate(hmac.trans_5C)) def F(i): u = salt + struct.pack(b'>I', i) result = 0 for j in range(int(iterations)): dig1, dig2 = inner.copy(), outer.copy() dig1.update(u) dig2.update(dig1.digest()) u = dig2.digest() result ^= _bin_to_long(u) return _long_to_bin(result, hex_format_string) T = [F(x) for x in range(1, l)] return b''.join(T) + F(l)[:r]
def encode(self, password, salt): bcrypt = self._load_library() # Hash the password prior to using bcrypt to prevent password # truncation as described in #20138. if self.digest is not None: # Use binascii.hexlify() because a hex encoded bytestring is # Unicode on Python 3. password = binascii.hexlify( self.digest(force_bytes(password)).digest()) else: password = force_bytes(password) data = bcrypt.hashpw(password, salt) return "%s$%s" % (self.algorithm, force_text(data))
def pbkdf2(password, salt, iterations, dklen=0, digest=None): """ Implements PBKDF2 with the same API as Orun's existing implementation, using the stdlib. This is used in Python 2.7.8+ and 3.4+. """ if digest is None: digest = hashlib.sha256 if not dklen: dklen = None password = force_bytes(password) salt = force_bytes(salt) return hashlib.pbkdf2_hmac( digest().name, password, salt, iterations, dklen)
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None, html_email_template_name=None, extra_email_context=None): """ Generate a one-use only link for resetting password and send it to the user. """ email = self.cleaned_data["email"] for user in self.get_users(email): if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override context = { 'email': email, 'domain': domain, 'site_name': site_name, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', **(extra_email_context or {}), } self.send_mail( subject_template_name, email_template_name, context, from_email, email, html_email_template_name=html_email_template_name, )
def truncate_name(name, length=None, hash_len=4): """Shortens a string to a repeatable mangled version with the given length. """ if length is None or len(name) <= length: return name hsh = hashlib.md5(force_bytes(name)).hexdigest()[:hash_len] return '%s%s' % (name[:length - hash_len], hsh)
def harden_runtime(self, password, encoded): _, data = encoded.split('$', 1) salt = data[:29] # Length of the salt in bcrypt. rounds = data.split('$')[2] # work factor is logarithmic, adding one doubles the load. diff = 2**(self.rounds - int(rounds)) - 1 while diff > 0: self.encode(password, force_bytes(salt)) diff -= 1
def _digest(cls, *args): """ Generates a 32-bit digest of a set of arguments that can be used to shorten identifying names. """ h = hashlib.md5() for arg in args: h.update(force_bytes(arg)) return h.hexdigest()[:8]
def urlsafe_base64_decode(s): """ Decodes a base64 encoded string, adding back any trailing equal signs that might have been stripped. """ s = force_bytes(s) try: return base64.urlsafe_b64decode(s.ljust(len(s) + len(s) % 4, b'=')) except (LookupError, BinasciiError) as e: raise ValueError(e)
def salted_hmac(key_salt, value, secret=None): """ Returns the HMAC-SHA1 of 'value', using a key generated from key_salt and a secret (which defaults to settings.SECRET_KEY). A different key_salt should be passed in for every application of HMAC. """ if secret is None: secret = settings.SECRET_KEY key_salt = force_bytes(key_salt) secret = force_bytes(secret) # 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 and # SHA1 works nicely. key = hashlib.sha1(key_salt + secret).digest() # If len(key_salt + secret) > sha_constructor().block_size, 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 hmac.new(key, msg=force_bytes(value), digestmod=hashlib.sha1)
def _create_index_name(self, model, column_names, suffix="", prefix=""): """ Generates a unique name for an index/unique constraint. """ # If there is just one column in the index, use a default algorithm from Orun if len(column_names) == 1 and not suffix: name = model._meta.table_name name = name.replace('"', '') if '.' in name: name = name.split('.')[1] ix_name = column_names[0] #ix_name = self._digest(column_names[0]) if name[-1] == '"': name = '%s%s_%s"' % (prefix, name[:-1], ix_name) else: name = '%s%s_%s' % (prefix, name, ix_name) return truncate_name(name, 127) # Else generate the name for the index using a different algorithm table_name = model._meta.db_table.replace('"', '').replace('.', '_') index_unique_name = '_%s' % self._digest(table_name, *column_names) max_length = self.connection.conn_info.ops.max_name_length() or 200 # If the index name is too long, truncate it index_name = ('%s%s_%s%s%s' % ( prefix, table_name, column_names[0], index_unique_name, suffix, )).replace('"', '').replace('.', '_') if len(index_name) > max_length: part = ('_%s%s%s' % (column_names[0], index_unique_name, suffix)) index_name = '%s%s' % (table_name[:(max_length - len(part))], part) # It shouldn't start with an underscore (Oracle hates this) if index_name[0] == "_": index_name = index_name[1:] # If it's STILL too long, just hash it down if len(index_name) > max_length: index_name = hashlib.md5(force_bytes(index_name)).hexdigest()[:max_length] # It can't start with a number on Oracle, so prepend D if we need to if index_name[0].isdigit(): index_name = "D%s" % index_name[:-1] return index_name
def verify(self, password, encoded): algorithm, data = encoded.split('$', 1) assert algorithm == self.algorithm encoded_2 = self.encode(password, force_bytes(data)) return constant_time_compare(encoded, encoded_2)
def convert_binaryfield_value(self, value, expression, connection, context): if isinstance(value, Database.LOB): value = force_bytes(value.read()) return value
def encode(self, password, salt): assert salt == '' return hashlib.md5(force_bytes(password)).hexdigest()
def encode(self, password, salt): assert salt == '' hash = hashlib.sha1(force_bytes(password)).hexdigest() return 'sha1$$%s' % hash
def encode(self, password, salt): assert password is not None assert salt and '$' not in salt hash = hashlib.md5(force_bytes(salt + password)).hexdigest() return "%s$%s$%s" % (self.algorithm, salt, hash)
def constant_time_compare(val1, val2): return hmac.compare_digest(force_bytes(val1), force_bytes(val2))