Example #1
0
 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")
Example #2
0
 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()
Example #3
0
 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()
Example #4
0
 def _render_record(self, key, hash):
     user, realm = key
     return render_bytes("%s:%s:%s\n", user, realm, hash)
Example #5
0
 def _render_record(self, user, hash):
     return render_bytes("%s:%s\n", user, hash)
Example #6
0
 def _render_record(self, key, hash):
     user, realm = key
     return render_bytes("%s:%s:%s\n", user, realm, hash)
Example #7
0
 def _render_record(self, user, hash):
     return render_bytes("%s:%s\n", user, hash)
Example #8
0
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")
Example #9
0
 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")
Example #10
0
 def _render_line(self, key, hash):
     return render_bytes("%s:%s:%s\n", key[0], key[1], hash)
Example #11
0
 def _render_line(self, user, hash):
     return render_bytes("%s:%s\n", user, hash)
Example #12
0
 def _render_line(self, key, hash):
     return render_bytes("%s:%s:%s\n", key[0], key[1], hash)
Example #13
0
 def _render_line(self, user, hash):
     return render_bytes("%s:%s\n", user, hash)