def _raw_sha2_crypt(pwd, salt, rounds, use_512=False): if isinstance(pwd, unicode): pwd = pwd.encode('utf-8') if _BNULL in pwd: raise uh.exc.NullPasswordError( sha512_crypt if use_512 else sha256_crypt) pwd_len = len(pwd) salt = salt.encode('ascii') salt_len = len(salt) if use_512: hash_const = hashlib.sha512 transpose_map = _512_transpose_map else: hash_const = hashlib.sha256 transpose_map = _256_transpose_map db = hash_const(pwd + salt + pwd).digest() a_ctx = hash_const(pwd + salt) a_ctx_update = a_ctx.update a_ctx_update(repeat_string(db, pwd_len)) i = pwd_len while i: a_ctx_update(db if i & 1 else pwd) i >>= 1 da = a_ctx.digest() if pwd_len < 96: dp = repeat_string(hash_const(pwd * pwd_len).digest(), pwd_len) else: tmp_ctx = hash_const(pwd) tmp_ctx_update = tmp_ctx.update i = pwd_len - 1 while i: tmp_ctx_update(pwd) i -= 1 dp = repeat_string(tmp_ctx.digest(), pwd_len) ds = hash_const(salt * (16 + byte_elem_value(da[0]))).digest()[:salt_len] dp_dp = dp + dp dp_ds = dp + ds perms = [dp, dp_dp, dp_ds, dp_ds + dp, ds + dp, ds + dp_dp] data = [(perms[even], perms[odd]) for even, odd in _c_digest_offsets] dc = da blocks, tail = divmod(rounds, 42) while blocks: for even, odd in data: dc = hash_const(odd + hash_const(dc + even).digest()).digest() blocks -= 1 if tail: pairs = tail >> 1 for even, odd in data[:pairs]: dc = hash_const(odd + hash_const(dc + even).digest()).digest() if tail & 1: dc = hash_const(dc + data[pairs][0]).digest() return h64.encode_transposed_bytes(dc, transpose_map).decode('ascii')
def _calc_checksum(self, secret): asa = self._is_asa if isinstance(secret, unicode): secret = secret.encode('utf-8') spoil_digest = None if len(secret) > self.truncate_size: if self.use_defaults: msg = 'Password too long (%s allows at most %d bytes)' % ( self.name, self.truncate_size) raise uh.exc.PasswordSizeError(self.truncate_size, msg=msg) else: spoil_digest = secret + _DUMMY_BYTES user = self.user if user: if isinstance(user, unicode): user = user.encode('utf-8') if not asa or len(secret) < 28: secret += repeat_string(user, 4) if asa and len(secret) > 16: pad_size = 32 else: pad_size = 16 secret = right_pad_string(secret, pad_size) if spoil_digest: secret += spoil_digest digest = md5(secret).digest() digest = join_byte_elems(c for i, c in enumerate(digest) if i + 1 & 3) return h64.encode_bytes(digest).decode('ascii')
def _norm_digest_args(cls, secret, ident, new=False): if isinstance(secret, unicode): secret = secret.encode('utf-8') uh.validate_secret(secret) if new: cls._check_truncate_policy(secret) if _BNULL in secret: raise uh.exc.NullPasswordError(cls) if cls._has_2a_wraparound_bug and len(secret) >= 255: secret = secret[:72] if ident == IDENT_2A: pass else: if ident == IDENT_2B: if cls._lacks_2b_support: ident = cls._fallback_ident else: if ident == IDENT_2Y: if cls._lacks_2y_support: ident = cls._fallback_ident else: if ident == IDENT_2: if cls._lacks_20_support: if secret: secret = repeat_string(secret, 72) ident = cls._fallback_ident else: if ident == IDENT_2X: raise RuntimeError( '$2x$ hashes not currently supported by passlib' ) else: raise AssertionError('unexpected ident value: %r' % ident) return (secret, ident)
def check_bcryptor(secret, hash): secret = to_native_str(secret, self.FuzzHashGenerator.password_encoding) if hash.startswith((IDENT_2B, IDENT_2Y)): hash = IDENT_2A + hash[4:] else: if hash.startswith(IDENT_2): hash = IDENT_2A + hash[3:] if secret: secret = repeat_string(secret, 72) return Engine(False).hash_key(secret, hash) == hash
def generate(self): opts = super(_bcrypt_test.FuzzHashGenerator, self).generate() secret = opts['secret'] other = opts['other'] settings = opts['settings'] ident = settings.get('ident') if ident == IDENT_2X: del settings['ident'] else: if ident == IDENT_2 and other and repeat_string( to_bytes(other), len( to_bytes(secret))) == to_bytes(secret): opts['secret'], opts['other'] = self.random_password_pair() return opts
def check_bcrypt(secret, hash): secret = to_bytes(secret, self.FuzzHashGenerator.password_encoding) if hash.startswith(IDENT_2B): hash = IDENT_2A + hash[4:] else: if hash.startswith(IDENT_2): hash = IDENT_2A + hash[3:] if secret: secret = repeat_string(secret, 72) else: if hash.startswith( IDENT_2Y) and bcrypt.__version__ == '3.0.0': hash = IDENT_2B + hash[4:] hash = to_bytes(hash) try: return bcrypt.hashpw(secret, hash) == hash except ValueError: raise ValueError('bcrypt rejected hash: %r (secret=%r)' % (hash, secret))
def _raw_md5_crypt(pwd, salt, use_apr=False): if isinstance(pwd, unicode): pwd = pwd.encode('utf-8') if _BNULL in pwd: raise uh.exc.NullPasswordError(md5_crypt) pwd_len = len(pwd) salt = salt.encode('ascii') if use_apr: magic = _APR_MAGIC else: magic = _MD5_MAGIC db = md5(pwd + salt + pwd).digest() a_ctx = md5(pwd + magic + salt) a_ctx_update = a_ctx.update a_ctx_update(repeat_string(db, pwd_len)) i = pwd_len evenchar = pwd[:1] while i: a_ctx_update(_BNULL if i & 1 else evenchar) i >>= 1 da = a_ctx.digest() pwd_pwd = pwd + pwd pwd_salt = pwd + salt perms = [ pwd, pwd_pwd, pwd_salt, pwd_salt + pwd, salt + pwd, salt + pwd_pwd ] data = [(perms[even], perms[odd]) for even, odd in _c_digest_offsets] dc = da blocks = 23 while blocks: for even, odd in data: dc = md5(odd + md5(dc + even).digest()).digest() blocks -= 1 for even, odd in data[:17]: dc = md5(odd + md5(dc + even).digest()).digest() return h64.encode_transposed_bytes(dc, _transpose_map).decode('ascii')
def key_to_words(data, size=18): dlen = len(data) if not dlen: return [0] * size data = repeat_string(data, size << 2) return struct.unpack('>%dI' % (size, ), data)
class _bcrypt_sha256_test(HandlerCase): handler = hash.bcrypt_sha256 reduce_default_rounds = True forbidden_characters = None fuzz_salts_need_bcrypt_repair = True alt_safe_crypt_handler = hash.bcrypt has_os_crypt_fallback = True known_correct_hashes = [ ('', '$bcrypt-sha256$2a,5$E/e/2AOhqM5W/KJTFQzLce$F6dYSxOdAEoJZO2eoHUZWZljW/e0TXO' ), ('password', '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu' ), (UPASS_TABLE, '$bcrypt-sha256$2a,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje' ), (UPASS_TABLE.encode('utf-8'), '$bcrypt-sha256$2a,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje' ), ('password', '$bcrypt-sha256$2b,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu' ), (UPASS_TABLE, '$bcrypt-sha256$2b,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje' ), (repeat_string('abc123', 72), '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$r/hyEtqJ0teqPEmfTLoZ83ciAI1Q74.' ), (repeat_string('abc123', 72) + 'qwr', '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$021KLEif6epjot5yoxk0m8I0929ohEa' ), (repeat_string('abc123', 72) + 'xyz', '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$7.1kgpHduMGEjvM3fX6e/QCvfn6OKja' ) ] known_correct_configs = [( '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe', 'password', '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu' )] known_malformed_hashes = [ '$bcrypt-sha256$2a,5$5Hg1DKF!PE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', '$bcrypt-sha256$2c,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', '$bcrypt-sha256$2x,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', '$bcrypt-sha256$2a,05$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$' ] def setUp(self): if TEST_MODE('full') and self.backend == 'builtin': key = 'PASSLIB_BUILTIN_BCRYPT' orig = os.environ.get(key) if orig: self.addCleanup(os.environ.__setitem__, key, orig) else: self.addCleanup(os.environ.__delitem__, key) os.environ[key] = 'enabled' super(_bcrypt_sha256_test, self).setUp() warnings.filterwarnings( 'ignore', '.*backend is vulnerable to the bsd wraparound bug.*') def populate_settings(self, kwds): if self.backend == 'builtin': kwds.setdefault('rounds', 4) super(_bcrypt_sha256_test, self).populate_settings(kwds) def test_30_HasManyIdents(self): raise self.skipTest('multiple idents not supported') def test_30_HasOneIdent(self): handler = self.handler handler(use_defaults=True) self.assertRaises(ValueError, handler, ident='$2y$', use_defaults=True) class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): def random_rounds(self): return self.randintgauss(5, 8, 6, 1)