def update_settings(**kwds): for k, v in iteritems(kwds): if v is UNSET: if hasattr(settings, k): delattr(settings, k) else: setattr(settings, k, v)
def verify(cls, secret, hash, full=False): uh.validate_secret(secret) self = cls.from_string(hash) chkmap = self.checksum if not chkmap: raise ValueError('expected %s hash, got %s config string instead' % ( cls.name, cls.name)) if full: correct = failed = False for alg, digest in iteritems(chkmap): other = self._calc_checksum(secret, alg) if len(digest) != len(other): raise ValueError('mis-sized %s digest in scram hash: %r != %r' % ( alg, len(digest), len(other))) if consteq(other, digest): correct = True else: failed = True if correct and failed: raise ValueError('scram hash verified inconsistently, may be corrupted') else: return correct else: for alg in self._verify_algs: if alg in chkmap: other = self._calc_checksum(secret, alg) return consteq(other, chkmap[alg]) raise AssertionError('sha-1 digest not found!')
def check_all(self, strict=False): same = self._is_same_value for path, (orig, expected) in iteritems(self._state): if same(self._get_path(path), expected): continue msg = 'another library has patched resource: %r' % path if strict: raise RuntimeError(msg) else: warn(msg, PasslibRuntimeWarning)
def safe_summary(self, encoded): from django.contrib.auth.hashers import mask_hash from django.utils.translation import ugettext_noop as _ handler = self.passlib_handler items = [(_('algorithm'), handler.name)] if hasattr(handler, 'parsehash'): kwds = handler.parsehash(encoded, sanitize=mask_hash) for key, value in iteritems(kwds): key = self._translate_kwds.get(key, key) items.append((_(key), value)) return OrderedDict(items)
def _init_options(self, source): norm_scheme_option = self._norm_scheme_option norm_context_option = self._norm_context_option self._scheme_options = scheme_options = {} self._context_options = context_options = {} categories = set() for (cat, scheme, key), value in iteritems(source): categories.add(cat) explicit_scheme = scheme if not cat and not scheme and key in _global_settings: scheme = 'all' if scheme: key, value = norm_scheme_option(key, value) if scheme == 'all' and key not in _global_settings: warn( "The '%s' option should be configured per-algorithm, and not set globally in the context; This will be an error in Passlib 2.0" % (key, ), PasslibConfigWarning) if explicit_scheme == 'all': warn( "The 'all' scheme is deprecated as of Passlib 1.7, and will be removed in Passlib 2.0; Please configure options on a per-algorithm basis.", DeprecationWarning) try: category_map = scheme_options[scheme] except KeyError: scheme_options[scheme] = {cat: {key: value}} else: try: option_map = category_map[cat] except KeyError: category_map[cat] = {key: value} else: option_map[key] = value else: if cat and key == 'schemes': raise KeyError( "'schemes' context option is not allowed per category") key, value = norm_context_option(cat, key, value) if key == 'min_verify_time': continue try: category_map = context_options[key] except KeyError: context_options[key] = {cat: value} else: category_map[cat] = value categories.discard(None) self.categories = tuple(sorted(categories)) return
def _norm_checksum(self, checksum, relaxed=False): if not isinstance(checksum, dict): raise uh.exc.ExpectedTypeError(checksum, 'dict', 'checksum') for alg, digest in iteritems(checksum): if alg != norm_hash_name(alg, 'iana'): raise ValueError('malformed algorithm name in scram hash: %r' % ( alg,)) if len(alg) > 9: raise ValueError('SCRAM limits algorithm names to 9 characters: %r' % ( alg,)) if not isinstance(digest, bytes): raise uh.exc.ExpectedTypeError(digest, 'raw bytes', 'digests') if 'sha-1' not in checksum: raise ValueError('sha-1 must be in algorithm list of scram hash') return checksum
def load(self, source, update=False, section='passlib', encoding='utf-8'): parse_keys = True if isinstance(source, unicode_or_bytes_types): if PY3: source = to_unicode(source, encoding, param='source') else: source = to_bytes(source, 'utf-8', source_encoding=encoding, param='source') source = self._parse_ini_stream( NativeStringIO(source), section, '<string passed to CryptContext.load()>') else: if isinstance(source, CryptContext): source = dict(source._config.iter_config(resolve=True)) parse_keys = False else: if not hasattr(source, 'items'): raise ExpectedTypeError(source, 'string or dict', 'source') if parse_keys: parse = self._parse_config_key source = dict( (parse(key), value) for key, value in iteritems(source)) if update and self._config is not None: if not source: return tmp = source source = dict(self._config.iter_config(resolve=True)) source.update(tmp) config = _CryptConfig(source) self._config = config self._reset_dummy_verify() self._get_record = config.get_record self._identify_record = config.identify_record if config.context_kwds: self.__dict__.pop('_strip_unused_context_kwds', None) else: self._strip_unused_context_kwds = None return
class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): name = 'fshp' setting_kwds = ('salt', 'salt_size', 'rounds', 'variant') checksum_chars = uh.PADDED_BASE64_CHARS ident = u('{FSHP') default_salt_size = 16 max_salt_size = None default_rounds = 480000 min_rounds = 1 max_rounds = 4294967295L rounds_cost = 'linear' default_variant = 1 _variant_info = {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) ]) @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 variant = None def __init__(self, variant=None, **kwds): self.use_defaults = kwds.get('use_defaults') if variant is not None: variant = self._norm_variant(variant) else: if self.use_defaults: variant = self.default_variant else: raise TypeError('no variant specified') self.variant = variant super(fshp, self).__init__(**kwds) return @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] _hash_regex = re.compile(u('\n ^\n \\{FSHP\n (\\d+)\\| # variant\n (\\d+)\\| # salt size\n (\\d+)\\} # rounds\n ([a-zA-Z0-9+/]+={0,3}) # digest\n $'), 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) def _calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode('utf-8') return pbkdf1(digest=self.checksum_alg, secret=self.salt, salt=secret, rounds=self.rounds, keylen=self.checksum_size)