def _calc_digest(self, user, realm, password): "helper to calculate digest" if isinstance(password, unicode): password = password.encode(self.password_encoding) #NOTE: encode('ascii') is noop under py2, required under py3 return md5(render_bytes("%s:%s:%s", user, realm, password)).hexdigest().encode("ascii")
def hash(cls, secret, user, realm, encoding=None): # NOTE: this was deliberately written so that raw bytes are passed through # unchanged, the encoding kwd is only used to handle unicode values. if not encoding: encoding = cls.default_encoding uh.validate_secret(secret) if isinstance(secret, unicode): secret = secret.encode(encoding) user = to_bytes(user, encoding, "user") realm = to_bytes(realm, encoding, "realm") data = render_bytes("%s:%s:%s", user, realm, secret) return hashlib.md5(data).hexdigest()
def encrypt(cls, secret, user, realm, encoding=None): # NOTE: this was deliberately written so that raw bytes are passed through # unchanged, the encoding kwd is only used to handle unicode values. if not encoding: encoding = cls.default_encoding uh.validate_secret(secret) if isinstance(secret, unicode): secret = secret.encode(encoding) user = to_bytes(user, encoding, "user") realm = to_bytes(realm, encoding, "realm") data = render_bytes("%s:%s:%s", user, realm, secret) return hashlib.md5(data).hexdigest()
def _render_record(self, key, hash): user, realm = key return render_bytes("%s:%s:%s\n", user, realm, hash)
def _render_record(self, user, hash): return render_bytes("%s:%s\n", user, hash)
class _CffiBackend(_Argon2Common): """ argon2_cffi backend """ # =================================================================== # backend loading # =================================================================== @classmethod def _load_backend_mixin(mixin_cls, name, dryrun): # make sure we write info to base class's __dict__, not that of a subclass assert mixin_cls is _CffiBackend # we automatically import this at top, so just grab info if _argon2_cffi is None: if _argon2_cffi_error: raise exc.PasslibSecurityError(_argon2_cffi_error) return False max_version = _argon2_cffi.low_level.ARGON2_VERSION log.debug( "detected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashes", _argon2_cffi.__version__, max_version) # build type map TypeEnum = _argon2_cffi.Type type_map = {} for type in ALL_TYPES: try: type_map[type] = getattr(TypeEnum, type.upper()) except AttributeError: # TYPE_ID support not added until v18.2 assert type not in ( TYPE_I, TYPE_D), "unexpected missing type: %r" % type mixin_cls._backend_type_map = type_map # set version info, and run common setup mixin_cls.version = mixin_cls.max_version = max_version return mixin_cls._finalize_backend_mixin(name, dryrun) # =================================================================== # primary methods # =================================================================== @classmethod def hash(cls, secret): # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. uh.validate_secret(secret) secret = to_bytes(secret, "utf-8") # XXX: doesn't seem to be a way to make this honor max_threads try: return bascii_to_str( _argon2_cffi.low_level.hash_secret( type=cls._get_backend_type(cls.type), memory_cost=cls.memory_cost, time_cost=cls.default_rounds, parallelism=cls.parallelism, salt=to_bytes(cls._generate_salt()), hash_len=cls.checksum_size, secret=secret, )) except _argon2_cffi.exceptions.HashingError as err: raise cls._adapt_backend_error(err) #: helper for verify() method below -- maps prefixes to type constants _byte_ident_map = dict( (render_bytes(b"$argon2%s$", type.encode("ascii")), type) for type in ALL_TYPES) @classmethod def verify(cls, secret, hash): # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. uh.validate_secret(secret) secret = to_bytes(secret, "utf-8") hash = to_bytes(hash, "ascii") # read type from start of hash # NOTE: don't care about malformed strings, lowlevel will throw error for us type = cls._byte_ident_map.get(hash[:1 + hash.find(b"$", 1)], TYPE_I) type_code = cls._get_backend_type(type) # XXX: doesn't seem to be a way to make this honor max_threads try: result = _argon2_cffi.low_level.verify_secret( hash, secret, type_code) assert result is True return True except _argon2_cffi.exceptions.VerifyMismatchError: return False except _argon2_cffi.exceptions.VerificationError as err: raise cls._adapt_backend_error(err, hash=hash) # NOTE: deprecated, will be removed in 2.0 @classmethod def genhash(cls, secret, config): # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. uh.validate_secret(secret) secret = to_bytes(secret, "utf-8") self = cls.from_string(config) # XXX: doesn't seem to be a way to make this honor max_threads try: result = bascii_to_str( _argon2_cffi.low_level.hash_secret( type=cls._get_backend_type(self.type), memory_cost=self.memory_cost, time_cost=self.rounds, parallelism=self.parallelism, salt=to_bytes(self.salt), hash_len=self.checksum_size, secret=secret, version=self.version, )) except _argon2_cffi.exceptions.HashingError as err: raise cls._adapt_backend_error(err, hash=config) if self.version == 0x10: # workaround: argon2 0x13 always returns "v=" segment, even for 0x10 hashes result = result.replace("$v=16$", "$") return result # =================================================================== # digest calculation # =================================================================== def _calc_checksum(self, secret): raise AssertionError("shouldn't be called under argon2_cffi backend")
def _render_line(self, key, hash): return render_bytes("%s:%s:%s\n", key[0], key[1], hash)
def _render_line(self, user, hash): return render_bytes("%s:%s\n", user, hash)