def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None): secret = to_bytes(secret, param='secret') salt = to_bytes(salt, param='salt') digest_info = lookup_hash(digest) digest_size = digest_info.digest_size if not isinstance(rounds, int_types): raise exc.ExpectedTypeError(rounds, 'int', 'rounds') if rounds < 1: raise ValueError('rounds must be at least 1') if keylen is None: keylen = digest_size else: if not isinstance(keylen, int_types): raise exc.ExpectedTypeError(keylen, 'int or None', 'keylen') else: if keylen < 1: raise ValueError('keylen must be at least 1') block_count = (keylen + digest_size - 1) // digest_size if block_count > MAX_UINT32: raise OverflowError('keylen too long for digest') if digest_info.supported_by_fastpbkdf2: return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) if digest_info.supported_by_hashlib_pbkdf2: return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) keyed_hmac = compile_hmac(digest, secret) calc_block = _get_pbkdf2_looper(digest_size) return join_bytes( calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds) for i in irange(1, block_count + 1))[:keylen]
def _norm_salt(cls, salt, relaxed=False): if cls._salt_is_bytes: if not isinstance(salt, bytes): raise exc.ExpectedTypeError(salt, 'bytes', 'salt') else: if not isinstance(salt, unicode): if isinstance(salt, bytes) and (PY2 or relaxed): salt = salt.decode('ascii') else: raise exc.ExpectedTypeError(salt, 'unicode', 'salt') sc = cls.salt_chars if sc is not None and any(c not in sc for c in salt): raise ValueError('invalid characters in %s salt' % cls.name) mn = cls.min_salt_size if mn and len(salt) < mn: msg = 'salt too small (%s requires %s %d %s)' % ( cls.name, 'exactly' if mn == cls.max_salt_size else '>=', mn, cls._salt_unit) raise ValueError(msg) mx = cls.max_salt_size if mx and len(salt) > mx: msg = 'salt too large (%s requires %s %d %s)' % ( cls.name, 'exactly' if mx == mn else '<=', mx, cls._salt_unit) if relaxed: warn(msg, PasslibHashWarning) salt = cls._truncate_salt(salt, mx) else: raise ValueError(msg) return salt
def pbkdf1(digest, secret, salt, rounds, keylen=None): const, digest_size, block_size = lookup_hash(digest) secret = to_bytes(secret, param='secret') salt = to_bytes(salt, param='salt') if not isinstance(rounds, int_types): raise exc.ExpectedTypeError(rounds, 'int', 'rounds') if rounds < 1: raise ValueError('rounds must be at least 1') if keylen is None: keylen = digest_size else: if not isinstance(keylen, int_types): raise exc.ExpectedTypeError(keylen, 'int or None', 'keylen') else: if keylen < 0: raise ValueError('keylen must be at least 0') else: if keylen > digest_size: raise ValueError( 'keylength too large for digest: %r > %r' % (keylen, digest_size)) block = secret + salt for _ in irange(rounds): block = const(block).digest() return block[:keylen]
def _load_settings(self): from django.conf import settings _UNSET = object() config = getattr(settings, 'PASSLIB_CONFIG', _UNSET) if config is _UNSET: config = getattr(settings, 'PASSLIB_CONTEXT', _UNSET) if config is _UNSET: config = 'passlib-default' if config is None: warn( "setting PASSLIB_CONFIG=None is deprecated, and support will be removed in Passlib 1.8, use PASSLIB_CONFIG='disabled' instead.", DeprecationWarning) config = 'disabled' else: if not isinstance(config, (unicode, bytes, dict)): raise exc.ExpectedTypeError(config, 'str or dict', 'PASSLIB_CONFIG') get_category = getattr(settings, 'PASSLIB_GET_CATEGORY', None) if get_category and not callable(get_category): raise exc.ExpectedTypeError(get_category, 'callable', 'PASSLIB_GET_CATEGORY') if config == 'disabled': self.enabled = False return self.__dict__.pop('enabled', None) if isinstance(config, str) and '\n' not in config: config = get_preset_config(config) if get_category: self.get_user_category = get_category else: self.__dict__.pop('get_category', None) self.context.load(config) self.reset_hashers() return
def des_encrypt_int_block(key, input, salt=0, rounds=1): if rounds < 1: raise ValueError('rounds must be positive integer') if salt < 0 or salt > INT_24_MASK: raise ValueError('salt must be 24-bit non-negative integer') if not isinstance(key, int_types): raise exc.ExpectedTypeError(key, 'int', 'key') else: if key < 0 or key > INT_64_MASK: raise ValueError('key must be 64-bit non-negative integer') if not isinstance(input, int_types): raise exc.ExpectedTypeError(input, 'int', 'input') else: if input < 0 or input > INT_64_MASK: raise ValueError('input must be 64-bit non-negative integer') if PCXROT is None: _load_tables() SPE0, SPE1, SPE2, SPE3, SPE4, SPE5, SPE6, SPE7 = SPE def _iter_key_schedule(ks_odd): for p_even, p_odd in PCXROT: ks_even = _permute(ks_odd, p_even) ks_odd = _permute(ks_even, p_odd) yield (ks_even & _KS_MASK, ks_odd & _KS_MASK) ks_list = list(_iter_key_schedule(key)) salt = (salt & 63) << 26 | (salt & 4032) << 12 | ( salt & 258048) >> 2 | (salt & 16515072) >> 16 if input == 0: L = R = 0 else: L = input >> 31 & 2863311530L | input & 1431655765 L = _permute(L, IE3264) R = input >> 32 & 2863311530L | input >> 1 & 1431655765 R = _permute(R, IE3264) while rounds: rounds -= 1 for ks_even, ks_odd in ks_list: k = (R >> 32 ^ R) & salt B = k << 32 ^ k ^ R ^ ks_even L ^= SPE0[(B >> 58 & 63)] ^ SPE1[(B >> 50 & 63)] ^ SPE2[( B >> 42 & 63)] ^ SPE3[(B >> 34 & 63)] ^ SPE4[( B >> 26 & 63)] ^ SPE5[(B >> 18 & 63)] ^ SPE6[( B >> 10 & 63)] ^ SPE7[(B >> 2 & 63)] k = (L >> 32 ^ L) & salt B = k << 32 ^ k ^ L ^ ks_odd R ^= SPE0[(B >> 58 & 63)] ^ SPE1[(B >> 50 & 63)] ^ SPE2[( B >> 42 & 63)] ^ SPE3[(B >> 34 & 63)] ^ SPE4[( B >> 26 & 63)] ^ SPE5[(B >> 18 & 63)] ^ SPE6[( B >> 10 & 63)] ^ SPE7[(B >> 2 & 63)] L, R = R, L C = L >> 3 & 1085102592318504960L | L << 33 & 17361641477096079360L | R >> 35 & 252645135 | R << 1 & 4042322160L return _permute(C, CF6464)
def norm_integer(handler, value, min=1, max=None, param='value', relaxed=False): if not isinstance(value, int_types): raise exc.ExpectedTypeError(value, 'integer', param) if value < min: msg = '%s: %s (%d) is too low, must be at least %d' % ( handler.name, param, value, min) if relaxed: warn(msg, exc.PasslibHashWarning) value = min else: raise ValueError(msg) if max and value > max: msg = '%s: %s (%d) is too large, cannot be more than %d' % ( handler.name, param, value, max) if relaxed: warn(msg, exc.PasslibHashWarning) value = max else: raise ValueError(msg) return value
def __call__(self, returns=None): if returns is None: return next(self) if isinstance(returns, int_types): return [ next(self) for _ in irange(returns) ] if returns is iter: return self raise exc.ExpectedTypeError(returns, '<None>, int, or <iter>', 'returns') return
def des_encrypt_block(key, input, salt=0, rounds=1): if isinstance(key, bytes): if len(key) == 7: key = expand_des_key(key) else: if len(key) != 8: raise ValueError('key must be 7 or 8 bytes') key = _unpack64(key) else: raise exc.ExpectedTypeError(key, 'bytes', 'key') if isinstance(input, bytes): if len(input) != 8: raise ValueError('input block must be 8 bytes') input = _unpack64(input) else: raise exc.ExpectedTypeError(input, 'bytes', 'input') result = des_encrypt_int_block(key, input, salt, rounds) return _pack64(result)
def normalize_time(cls, time): if isinstance(time, int_types): return time if isinstance(time, float): return int(time) if time is None: return int(cls.now()) if hasattr(time, 'utctimetuple'): return calendar.timegm(time.utctimetuple()) raise exc.ExpectedTypeError(time, 'int, float, or datetime', 'time') return
def _decode_bytes(key, format): if format == 'raw': if not isinstance(key, bytes): raise exc.ExpectedTypeError(key, 'bytes', 'key') return key key = to_unicode(key, param='key') key = _clean_re.sub('', key).encode('utf-8') if format == 'hex' or format == 'base16': return base64.b16decode(key.upper()) if format == 'base32': return b32decode(key) raise ValueError('unknown byte-encoding format: %r' % (format, ))
def expand_des_key(key): if isinstance(key, bytes): if len(key) != 7: raise ValueError('key must be 7 bytes in size') else: if isinstance(key, int_types): if key < 0 or key > INT_56_MASK: raise ValueError('key must be 56-bit non-negative integer') return _unpack64(expand_des_key(_pack56(key))) raise exc.ExpectedTypeError(key, 'bytes or int', 'key') key = _unpack56(key) return join_byte_values( (key >> shift & 127) << 1 for shift in _EXPAND_ITER)
def _norm_checksum(self, checksum, relaxed=False): raw = self._checksum_is_bytes if raw: if not isinstance(checksum, bytes): raise exc.ExpectedTypeError(checksum, 'bytes', 'checksum') else: if not isinstance(checksum, unicode): if isinstance(checksum, bytes) and relaxed: warn('checksum should be unicode, not bytes', PasslibHashWarning) checksum = checksum.decode('ascii') else: raise exc.ExpectedTypeError(checksum, 'unicode', 'checksum') cc = self.checksum_size if cc and len(checksum) != cc: raise exc.ChecksumSizeError(self, raw=raw) if not raw: cs = self.checksum_chars if cs and any(c not in cs for c in checksum): raise ValueError('invalid characters in %s checksum' % (self.name, )) return checksum
def lookup_hash(digest, return_unknown=False): cache = _hash_info_cache try: return cache[digest] except (KeyError, TypeError): pass else: cache_by_name = True if isinstance(digest, unicode_or_bytes_types): name_list = _get_hash_aliases(digest) name = name_list[0] if name != digest: info = lookup_hash(name, return_unknown=return_unknown) if info.const is None: return info cache[digest] = info return info const = _get_hash_const(name) if const is None: if return_unknown: return HashInfo(None, name_list) raise exc.UnknownHashError(name) else: if isinstance(digest, HashInfo): return digest if callable(digest): const = digest name_list = _get_hash_aliases(const().name) name = name_list[0] other_const = _get_hash_const(name) if other_const is None: pass elif other_const is const: pass else: cache_by_name = False else: raise exc.ExpectedTypeError(digest, 'digest name or constructor', 'digest') info = HashInfo(const, name_list) cache[const] = info if cache_by_name: for name in name_list: if name: cache[name] = info return info
def shrink_des_key(key): if isinstance(key, bytes): if len(key) != 8: raise ValueError('key must be 8 bytes in size') return _pack56(shrink_des_key(_unpack64(key))) if isinstance(key, int_types): if key < 0 or key > INT_64_MASK: raise ValueError('key must be 64-bit non-negative integer') else: raise exc.ExpectedTypeError(key, 'bytes or int', 'key') key >>= 1 result = 0 offset = 0 while offset < 56: result |= (key & 127) << offset key >>= 8 offset += 7 return result
def using(cls, digits=None, alg=None, period=None, issuer=None, wallet=None, now=None, **kwds): subcls = type('TOTP', (cls, ), {}) def norm_param(attr, value): kwds = dict(key=_DUMMY_KEY, format='raw') kwds[attr] = value obj = subcls(**kwds) return getattr(obj, attr) if digits is not None: subcls.digits = norm_param('digits', digits) if alg is not None: subcls.alg = norm_param('alg', alg) if period is not None: subcls.period = norm_param('period', period) if issuer is not None: subcls.issuer = norm_param('issuer', issuer) if kwds: subcls.wallet = AppWallet(**kwds) if wallet: raise TypeError( "'wallet' and 'secrets' keywords are mutually exclusive") else: if wallet is not None: if not isinstance(wallet, AppWallet): raise exc.ExpectedTypeError(wallet, AppWallet, 'wallet') subcls.wallet = wallet if now is not None: subcls.now = staticmethod(now) return subcls
def key(self, value): if not isinstance(value, bytes): raise exc.ExpectedTypeError(value, bytes, 'key') self._key = value self._encrypted_key = self._keyed_hmac = None return
def _check_serial(value, param, minval=0): if not isinstance(value, int_types): raise exc.ExpectedTypeError(value, 'int', param) if value < minval: raise ValueError('%s must be >= %d' % (param, minval))
def _resolve(hasher, param='value'): if is_crypt_handler(hasher): return hasher if isinstance(hasher, unicode_or_str): return get_crypt_handler(hasher) raise exc.ExpectedTypeError(hasher, unicode_or_str, param)