def to_string(self): ident = self.ident if ident == IDENT_SCRYPT: return "$scrypt$ln=%d,r=%d,p=%d$%s$%s" % ( self.rounds, self.block_size, self.parallelism, bascii_to_str(b64s_encode(self.salt)), bascii_to_str(b64s_encode(self.checksum)), ) else: assert ident == IDENT_7 salt = self.salt try: salt.decode("ascii") except UnicodeDecodeError: raise suppress_cause( NotImplementedError( "scrypt $7$ hashes dont support non-ascii salts")) return bascii_to_str(b"".join([ b"$7$", h64.encode_int6(self.rounds), h64.encode_int30(self.block_size), h64.encode_int30(self.parallelism), self.salt, b"$", h64.encode_bytes(self.checksum) ]))
def _calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") # check for truncation (during .hash() calls only) if self.use_defaults: self._check_truncate_policy(secret) # parse salt value try: salt_value = h64.decode_int12(self.salt.encode("ascii")) except ValueError: # pragma: no cover - caught by class raise suppress_cause(ValueError("invalid chars in salt")) # convert first 8 byts of secret string into an integer, key1 = _crypt_secret_to_key(secret) # run data through des using input of 0 result1 = des_encrypt_int_block(key1, 0, salt_value, 20) # convert next 8 bytes of secret string into integer (key=0 if secret < 8 chars) key2 = _crypt_secret_to_key(secret[8:16]) # run data through des using input of 0 result2 = des_encrypt_int_block(key2, 0, salt_value, 5) # done chk = h64big.encode_int64(result1) + h64big.encode_int64(result2) return chk.decode("ascii")
def ab64_decode(data): """ decode from shortened base64 format which omits padding & whitespace. uses custom ``./`` altchars, but supports decoding normal ``+/`` altchars as well. it is primarily used by Passlib's custom pbkdf2 hashes. """ if isinstance(data, unicode): # needs bytes for replace() call, but want to accept ascii-unicode ala a2b_base64() try: data = data.encode("ascii") except UnicodeEncodeError: raise suppress_cause(ValueError("string argument should contain only ASCII characters")) return b64s_decode(data.replace(b".", b"+"))
def b64s_decode(data): """ decode from shortened base64 format which omits padding & whitespace. uses default ``+/`` altchars. """ if isinstance(data, unicode): # needs bytes for replace() call, but want to accept ascii-unicode ala a2b_base64() try: data = data.encode("ascii") except UnicodeEncodeError: raise suppress_cause(ValueError("string argument should contain only ASCII characters")) off = len(data) & 3 if off == 0: pass elif off == 2: data += _BASE64_PAD2 elif off == 3: data += _BASE64_PAD1 else: # off == 1 raise ValueError("invalid base64 input") try: return a2b_base64(data) except _BinAsciiError as err: raise suppress_cause(TypeError(err))
def using(cls, block_size=None, **kwds): subcls = super(scrypt, cls).using(**kwds) if block_size is not None: if isinstance(block_size, uh.native_string_types): block_size = int(block_size) subcls.block_size = subcls._norm_block_size( block_size, relaxed=kwds.get("relaxed")) # make sure param combination is valid for scrypt() try: _scrypt.validate(1 << cls.default_rounds, cls.block_size, cls.parallelism) except ValueError as err: raise suppress_cause( ValueError("scrypt: invalid settings combination: " + str(err))) return subcls