mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Initial commit
This commit is contained in:
214
venv/Lib/site-packages/passlib/handlers/fshp.py
Normal file
214
venv/Lib/site-packages/passlib/handlers/fshp.py
Normal file
@@ -0,0 +1,214 @@
|
||||
"""passlib.handlers.fshp
|
||||
"""
|
||||
|
||||
#=============================================================================
|
||||
# imports
|
||||
#=============================================================================
|
||||
# core
|
||||
from base64 import b64encode, b64decode
|
||||
import re
|
||||
import logging; log = logging.getLogger(__name__)
|
||||
# site
|
||||
# pkg
|
||||
from passlib.utils import to_unicode
|
||||
import passlib.utils.handlers as uh
|
||||
from passlib.utils.compat import bascii_to_str, iteritems, u,\
|
||||
unicode
|
||||
from passlib.crypto.digest import pbkdf1
|
||||
# local
|
||||
__all__ = [
|
||||
'fshp',
|
||||
]
|
||||
#=============================================================================
|
||||
# sha1-crypt
|
||||
#=============================================================================
|
||||
class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
|
||||
"""This class implements the FSHP password hash, and follows the :ref:`password-hash-api`.
|
||||
|
||||
It supports a variable-length salt, and a variable number of rounds.
|
||||
|
||||
The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:
|
||||
|
||||
:param salt:
|
||||
Optional raw salt string.
|
||||
If not specified, one will be autogenerated (this is recommended).
|
||||
|
||||
:param salt_size:
|
||||
Optional number of bytes to use when autogenerating new salts.
|
||||
Defaults to 16 bytes, but can be any non-negative value.
|
||||
|
||||
:param rounds:
|
||||
Optional number of rounds to use.
|
||||
Defaults to 480000, must be between 1 and 4294967295, inclusive.
|
||||
|
||||
:param variant:
|
||||
Optionally specifies variant of FSHP to use.
|
||||
|
||||
* ``0`` - uses SHA-1 digest (deprecated).
|
||||
* ``1`` - uses SHA-2/256 digest (default).
|
||||
* ``2`` - uses SHA-2/384 digest.
|
||||
* ``3`` - uses SHA-2/512 digest.
|
||||
|
||||
:type relaxed: bool
|
||||
:param relaxed:
|
||||
By default, providing an invalid value for one of the other
|
||||
keywords will result in a :exc:`ValueError`. If ``relaxed=True``,
|
||||
and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
|
||||
will be issued instead. Correctable errors include ``rounds``
|
||||
that are too small or too large, and ``salt`` strings that are too long.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
"""
|
||||
|
||||
#===================================================================
|
||||
# class attrs
|
||||
#===================================================================
|
||||
#--GenericHandler--
|
||||
name = "fshp"
|
||||
setting_kwds = ("salt", "salt_size", "rounds", "variant")
|
||||
checksum_chars = uh.PADDED_BASE64_CHARS
|
||||
ident = u("{FSHP")
|
||||
# checksum_size is property() that depends on variant
|
||||
|
||||
#--HasRawSalt--
|
||||
default_salt_size = 16 # current passlib default, FSHP uses 8
|
||||
max_salt_size = None
|
||||
|
||||
#--HasRounds--
|
||||
# FIXME: should probably use different default rounds
|
||||
# based on the variant. setting for default variant (sha256) for now.
|
||||
default_rounds = 480000 # current passlib default, FSHP uses 4096
|
||||
min_rounds = 1 # set by FSHP
|
||||
max_rounds = 4294967295 # 32-bit integer limit - not set by FSHP
|
||||
rounds_cost = "linear"
|
||||
|
||||
#--variants--
|
||||
default_variant = 1
|
||||
_variant_info = {
|
||||
# variant: (hash name, digest size)
|
||||
0: ("sha1", 20),
|
||||
1: ("sha256", 32),
|
||||
2: ("sha384", 48),
|
||||
3: ("sha512", 64),
|
||||
}
|
||||
_variant_aliases = dict(
|
||||
[(unicode(k),k) for k in _variant_info] +
|
||||
[(v[0],k) for k,v in iteritems(_variant_info)]
|
||||
)
|
||||
|
||||
#===================================================================
|
||||
# configuration
|
||||
#===================================================================
|
||||
@classmethod
|
||||
def using(cls, variant=None, **kwds):
|
||||
subcls = super(fshp, cls).using(**kwds)
|
||||
if variant is not None:
|
||||
subcls.default_variant = cls._norm_variant(variant)
|
||||
return subcls
|
||||
|
||||
#===================================================================
|
||||
# instance attrs
|
||||
#===================================================================
|
||||
variant = None
|
||||
|
||||
#===================================================================
|
||||
# init
|
||||
#===================================================================
|
||||
def __init__(self, variant=None, **kwds):
|
||||
# NOTE: variant must be set first, since it controls checksum size, etc.
|
||||
self.use_defaults = kwds.get("use_defaults") # load this early
|
||||
if variant is not None:
|
||||
variant = self._norm_variant(variant)
|
||||
elif self.use_defaults:
|
||||
variant = self.default_variant
|
||||
assert self._norm_variant(variant) == variant, "invalid default variant: %r" % (variant,)
|
||||
else:
|
||||
raise TypeError("no variant specified")
|
||||
self.variant = variant
|
||||
super(fshp, self).__init__(**kwds)
|
||||
|
||||
@classmethod
|
||||
def _norm_variant(cls, variant):
|
||||
if isinstance(variant, bytes):
|
||||
variant = variant.decode("ascii")
|
||||
if isinstance(variant, unicode):
|
||||
try:
|
||||
variant = cls._variant_aliases[variant]
|
||||
except KeyError:
|
||||
raise ValueError("invalid fshp variant")
|
||||
if not isinstance(variant, int):
|
||||
raise TypeError("fshp variant must be int or known alias")
|
||||
if variant not in cls._variant_info:
|
||||
raise ValueError("invalid fshp variant")
|
||||
return variant
|
||||
|
||||
@property
|
||||
def checksum_alg(self):
|
||||
return self._variant_info[self.variant][0]
|
||||
|
||||
@property
|
||||
def checksum_size(self):
|
||||
return self._variant_info[self.variant][1]
|
||||
|
||||
#===================================================================
|
||||
# formatting
|
||||
#===================================================================
|
||||
|
||||
_hash_regex = re.compile(u(r"""
|
||||
^
|
||||
\{FSHP
|
||||
(\d+)\| # variant
|
||||
(\d+)\| # salt size
|
||||
(\d+)\} # rounds
|
||||
([a-zA-Z0-9+/]+={0,3}) # digest
|
||||
$"""), re.X)
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, hash):
|
||||
hash = to_unicode(hash, "ascii", "hash")
|
||||
m = cls._hash_regex.match(hash)
|
||||
if not m:
|
||||
raise uh.exc.InvalidHashError(cls)
|
||||
variant, salt_size, rounds, data = m.group(1,2,3,4)
|
||||
variant = int(variant)
|
||||
salt_size = int(salt_size)
|
||||
rounds = int(rounds)
|
||||
try:
|
||||
data = b64decode(data.encode("ascii"))
|
||||
except TypeError:
|
||||
raise uh.exc.MalformedHashError(cls)
|
||||
salt = data[:salt_size]
|
||||
chk = data[salt_size:]
|
||||
return cls(salt=salt, checksum=chk, rounds=rounds, variant=variant)
|
||||
|
||||
def to_string(self):
|
||||
chk = self.checksum
|
||||
salt = self.salt
|
||||
data = bascii_to_str(b64encode(salt+chk))
|
||||
return "{FSHP%d|%d|%d}%s" % (self.variant, len(salt), self.rounds, data)
|
||||
|
||||
#===================================================================
|
||||
# backend
|
||||
#===================================================================
|
||||
|
||||
def _calc_checksum(self, secret):
|
||||
if isinstance(secret, unicode):
|
||||
secret = secret.encode("utf-8")
|
||||
# NOTE: for some reason, FSHP uses pbkdf1 with password & salt reversed.
|
||||
# this has only a minimal impact on security,
|
||||
# but it is worth noting this deviation.
|
||||
return pbkdf1(
|
||||
digest=self.checksum_alg,
|
||||
secret=self.salt,
|
||||
salt=secret,
|
||||
rounds=self.rounds,
|
||||
keylen=self.checksum_size,
|
||||
)
|
||||
|
||||
#===================================================================
|
||||
# eoc
|
||||
#===================================================================
|
||||
|
||||
#=============================================================================
|
||||
# eof
|
||||
#=============================================================================
|
Reference in New Issue
Block a user