def scramble_salt(self, password, salt, server_key, client_key, rounds=None): """Scrambles a given salt using the specified server key. """ msg = salt + server_key + client_key hmac_digest = self.salt_key(password, salt, rounds) hash = Hash(self.ALGORITHM(), self.backend) hash.update(hmac_digest) hash_digest = hash.finalize() key_hash = Hash(self.ALGORITHM(), self.backend) key_hash.update(hash_digest) key_hash_digest = key_hash.finalize() sig = HMAC(key_hash_digest, self.ALGORITHM(), self.backend) sig.update(msg) sig_digest = sig.finalize() return self.xor(sig_digest, hash_digest)
def double_sha256(bytestr): hash1 = Hash(SHA256, DEFAULT_BACKEND) hash1.update(bytestr) hash1 = hash1.finalize() hash2 = Hash(SHA256, DEFAULT_BACKEND) hash2.update(hash1) hash2 = hash2.finalize() return hash2
def decrypt(secret, hash, data, file=False): """ Decrypt per telegram docs at https://core.telegram.org/passport. Args: secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a base64 encoded string. hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a base64 encoded string. data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a base64 encoded string. file (:obj:`bool`): Force data to be treated as raw data, instead of trying to b64decode it. Raises: :class:`TelegramDecryptionError`: Given hash does not match hash of decrypted data. Returns: :obj:`bytes`: The decrypted data as bytes. """ # First make sure that if secret, hash, or data was base64 encoded, to decode it into bytes try: secret = b64decode(secret) except (binascii.Error, TypeError): pass try: hash = b64decode(hash) except (binascii.Error, TypeError): pass if not file: try: data = b64decode(data) except (binascii.Error, TypeError): pass # Make a SHA512 hash of secret + update digest = Hash(SHA512(), backend=default_backend()) digest.update(secret + hash) secret_hash_hash = digest.finalize() # First 32 chars is our key, next 16 is the initialisation vector key, iv = secret_hash_hash[:32], secret_hash_hash[32:32 + 16] # Init a AES-CBC cipher and decrypt the data cipher = Cipher(AES(key), CBC(iv), backend=default_backend()) decryptor = cipher.decryptor() data = decryptor.update(data) + decryptor.finalize() # Calculate SHA256 hash of the decrypted data digest = Hash(SHA256(), backend=default_backend()) digest.update(data) data_hash = digest.finalize() # If the newly calculated hash did not match the one telegram gave us if data_hash != hash: # Raise a error that is caught inside telegram.PassportData and transformed into a warning raise TelegramDecryptionError("Hashes are not equal! {} != {}".format(data_hash, hash)) # Return data without padding return data[bord(data[0]):]
def derive(self, key_material): if not isinstance(key_material, bytes): raise TypeError("key_material must be bytes.") h = Hash(self._algorithm(), backend=self._backend) h.update(key_material) h.update(self._salt) derived_key = h.finalize() for i in xrange(self._iterations - 1): h = Hash(self._algorithm(), backend=self._backend) h.update(derived_key) derived_key = h.finalize() return derived_key
def check_pcrs(self, pcrs, qinfo, halg): if not qinfo.pcrSelect.count == 1: raise Exception('too many PCR selections') parray = TPMS_PCR_SELECTION_ARRAY.frompointer( qinfo.pcrSelect.pcrSelections) pcrsel = parray[0] if not pcrsel.hash == TPM2_ALG_SHA256: # FIXME raise Exception('PCR bank does not match') h = Hash(halg(), default_backend()) sel = 0 for ps, v in pcrs.items(): # FIXME, check keys p = int(ps) sel = sel | (1 << p) pv = b16decode(v) h.update(pv) dig = h.finalize() selb = sel.to_bytes(pcrsel.sizeofSelect, 'big') qselb = bytearray() qsarray = BYTE_ARRAY.frompointer(pcrsel.pcrSelect) for i in range(0, pcrsel.sizeofSelect): qselb.append(qsarray[i]) qselb = bytes(qselb) if not qselb == selb: raise Exception('PCR selection does not match') qdig = buffer_to_bytes(qinfo.pcrDigest) if not dig == qdig: raise Exception('PCR digest does not match')
def setup_cipher_rc4(salt, password, encrypt=False): hash = Hash(SHA1(), default_backend()) hash.update(salt + bytes(password, 'ascii')) cipher = Cipher(algorithms.ARC4(hash.finalize()), None, default_backend()) cryptor = cipher.encryptor() if encrypt else cipher.decryptor() cryptor.update(bytes(RC4_SKIP)) return cryptor
def validate_access_token(access_token, access_scope=scopes['client']): try: token = tokenserializer.loads(access_token) client_id = token.get('client', None) if not client_id: raise BadSignature('Token does not contain a client ID.') client = User.query.filter(User.id == client_id).first() if not client: raise BadSignature('No such client.') h = Hash(SHA256(), default_backend()) h.update(access_token.encode('utf-8')) if not client.token == h.finalize(): abort(401, message='Invalid access token.') if token.get('scope') > access_scope: abort(403, message='Insufficient Privileges.') except SignatureExpired: abort(401, message='Expired access token.') except BadSignature: abort(401, message='Bad access token.') except: raise
def _get_ciphertext_digest(ciphertext): if type(ciphertext) is str: ciphertext = bytes(ciphertext, 'utf-8') hash_provider = Hash(SHA512(), default_backend()) hash_provider.update(ciphertext) return base64.b64encode( hash_provider.finalize()).decode('utf-8').rstrip("=")
def decrypt_ec(data, ec_private_key): ephemeral_public_key = load_ec_public_key(data[:65]) shared_secret = ec_private_key.exchange(ec.ECDH(), ephemeral_public_key) digest = Hash(SHA256(), backend=_CRYPTO_BACKEND) digest.update(shared_secret) encryption_key = digest.finalize() return decrypt_aes_v2(data[65:], encryption_key)
def _rebuild_index(self): index = {} cipher = CipherContext(self._password) for path in self._secrets.glob('*.secret'): with open(path, 'rb') as file: contents = file.read() plaintext = decompress(cipher.decrypt(contents)) # We extract the path out of the plaintext first. path_size = unpack('>H', plaintext[:2])[0] short_path = plaintext[2:path_size + 2].decode() # This is the true plaintext. plaintext = plaintext[path_size + 2:] # We need to generate a hash for the file. hasher = Hash(BLAKE2b(64)) hasher.update(plaintext) index[short_path] = { 'path': short_path, 'uuid': path.stem, 'checksum': hasher.finalize().hex() } return index
def onion_name(key): pub_bytes = key.public_key().public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.PKCS1) hash = Hash(SHA1(), backend=default_backend()) hash.update(pub_bytes) return b32encode(hash.finalize()[:10]).lower().decode('ascii') + '.onion'
def decrypt_encryption_key_fallback(self): """Decrypts the encryption key using the FALLBACK method. In this method, the context string, usually "CredEncryption" or "PSEEncryption", is encrypted using a derivation of a fixed key hardcoded in CommonCryptoLib, and used as key to encrypt the actual encryption key used in the file with the AES cipher. :return: Encryption key decrypted :rtype: string """ log_lps.debug("Obtaining encryption key with FALLBACK LPS mode") digest = Hash(SHA1(), backend=default_backend()) digest.update(cred_key_lps_fallback) hashed_key = digest.finalize() hmac = HMAC(hashed_key, SHA1(), backend=default_backend()) hmac.update(self.context) default_key = hmac.finalize()[:16] iv = "\x00" * 16 decryptor = Cipher(algorithms.AES(default_key), modes.CBC(iv), backend=default_backend()).decryptor() encryption_key = decryptor.update( self.encrypted_key) + decryptor.finalize() return encryption_key
def hash(self, data): digest = Hash(MD5(), backend=openssl_backend) to_hash = "data={}||lpv={}||{}".format( data.decode('ascii'), '.'.join(map(str, self.version)), self.key) digest.update(to_hash.encode('utf8')) intermediate = digest.finalize().hex() return intermediate[8:24]
def encrypt_request(self, serialized_request): padder = self.session_key_padding.padder() serialized_request_padded = padder.update(serialized_request) + padder.finalize() encryptor = self.session_key_cipher.encryptor() serialized_request_ciphertext = encryptor.update(serialized_request_padded) + encryptor.finalize() hasher = Hash(self.digest_algorithm) hasher.update(serialized_request) serialized_request_digest = hasher.finalize() session_key_ciphertext = self.c2_public_key.encrypt( self.session_key, OAEP(MGF1(self.digest_algorithm), self.digest_algorithm, None), ) session_key_ciphertext_size = self.c2_public_key.key_size // 8 serialized_request_digest_size = self.digest_algorithm.digest_size serialized_request_ciphertext_size = len(serialized_request_ciphertext) encrypted_request = struct.pack( '<%ds%ds%ds' % ( session_key_ciphertext_size, serialized_request_digest_size, serialized_request_ciphertext_size ), session_key_ciphertext, serialized_request_digest, serialized_request_ciphertext, ) return encrypted_request
def decrypt(secret, hash, data): """ Decrypt per telegram docs at https://core.telegram.org/passport. Args: secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a base64 encoded string. hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a base64 encoded string. data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a base64 encoded string. file (:obj:`bool`): Force data to be treated as raw data, instead of trying to b64decode it. Raises: :class:`PassportDecryptionError`: Given hash does not match hash of decrypted data. Returns: :obj:`bytes`: The decrypted data as bytes. """ if not CRYPTO_INSTALLED: raise RuntimeError( "To use Telegram Passports, PTB must be installed via `pip install " "python-telegram-bot[passport]`." ) # Make a SHA512 hash of secret + update digest = Hash(SHA512(), backend=default_backend()) digest.update(secret + hash) secret_hash_hash = digest.finalize() # First 32 chars is our key, next 16 is the initialisation vector key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16] # Init a AES-CBC cipher and decrypt the data cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend()) decryptor = cipher.decryptor() data = decryptor.update(data) + decryptor.finalize() # Calculate SHA256 hash of the decrypted data digest = Hash(SHA256(), backend=default_backend()) digest.update(data) data_hash = digest.finalize() # If the newly calculated hash did not match the one telegram gave us if data_hash != hash: # Raise a error that is caught inside telegram.PassportData and transformed into a warning raise PassportDecryptionError(f"Hashes are not equal! {data_hash} != {hash}") # Return data without padding return data[data[0] :]
def encrypt_ec(data, ec_public_key): e_private_key, e_public_key = generate_ec_key() shared_secret = e_private_key.exchange(ec.ECDH(), ec_public_key) digest = Hash(SHA256(), backend=_CRYPTO_BACKEND) digest.update(shared_secret) encryption_key = digest.finalize() return unload_ec_public_key(e_public_key) + encrypt_aes_v2( data, encryption_key)
def setup_cipher_aes(salt, password, encrypt=False): hash = Hash(SHA256(), default_backend()) hash.update(salt + bytes(password, 'ascii')) cipher = Cipher(algorithms.AES(hash.finalize()[:16]), modes.CTR(salt[:16]), default_backend()) cryptor = cipher.encryptor() if encrypt else cipher.decryptor() cryptor.update(bytes(AES_SKIP)) return cryptor
def __init__(self, mail, password, scope=scopes['client']): self.email = mail self.scope = scope h = Hash(SHA256(), default_backend()) h.update(password.encode('utf-8')) self.password = h.finalize()
def hash_password(password: str, salt: str) -> str: """ Generates the password hash for the given user :param password: The password to hash :param salt: The salt(base64) to use in hash :return: The password hash """ hash_ = Hash(SHA3_512()) hash_.update(password.encode('ascii') + b64decode(salt.encode('ascii'))) digest = hash_.finalize() hash_ = Hash(SHA3_512()) hash_.update(digest) digest = hash_.finalize() hash_ = Hash(SHA3_512()) hash_.update(digest + b64decode(salt.encode('ascii'))) digest = hash_.finalize() return b64encode(digest).decode('ascii')
def get_public_key_digest(self): pem_public_key = self.get_pem_public_key() pem_public_key = [x for x in pem_public_key if len(x) > 0] pem_public_key.pop(0) pem_public_key.pop(-1) key_string = ''.join(pem_public_key) hash_provider = Hash(SHA512(), default_backend()) hash_provider.update(bytes(key_string, 'utf-8')) return binascii.hexlify(hash_provider.finalize())
def get_name(area): halg = tpm2_to_crypto_alg(area.nameAlg) algp = area.nameAlg.to_bytes(2, 'big') pbuf = marshal(area) h = Hash(halg(), default_backend()) h.update(pbuf) dig = h.finalize() name = algp + dig return name
def opdata1_decrypt_master_key(data, key, hmac_key, aes_size=C_AES_SIZE, ignore_hmac=False): key_size = KEY_SIZE[aes_size] bare_key = opdata1_decrypt_item(data, key, hmac_key, aes_size=aes_size, ignore_hmac=ignore_hmac) # XXX: got the following step from jeff@agilebits (as opposed to the # docs anywhere) digest = Hash(SHA512(), backend=_backend) digest.update(bare_key) hashed_key = digest.finalize() return hashed_key[:key_size], hashed_key[key_size:]
def compute_hash(cls, data: bytes) -> bytes: h = Hash(algorithm=cls.get_hash_func(), backend=default_backend()) h.update(data) digest = h.finalize() if cls.trunc_size: digest = digest[:cls.trunc_size] return digest
def sha512(self, plaintext): """ Perform SHA-512 hash """ digest = Hash(SHA512(), backend=default_backend()) digest.update(bytes(plaintext.encode('UTF-8'))) hash = digest.finalize() #return binascii.hexlify(bytearray(hash)) return base64.b16encode(hash).decode()
def __init__(self, data_secret: bytes, data_hash: bytes) -> None: digest = Hash(SHA512()) digest.update(data_secret) digest.update(data_hash) secret_hash = digest.finalize() key = secret_hash[:self._key_size] iv = secret_hash[self._key_size:self._key_size + self._iv_size] self._data_hash: Final[bytes] = data_hash self._cipher: Final[Cipher] = Cipher(AES(key), CBC(iv))
def sha256(message): """Generates a SHA256 hash of a message""" if isinstance(message, str): message = bytes(message, encoding='utf-8') elif isinstance(message, bytearray): message = bytes(message) digest = Hash(SHA256(), backend=default_backend()) digest.update(message) return digest.finalize()
def decrypt(self, ciphertext: bytes) -> bytes: decryptor = self._cipher.decryptor() # type: ignore assert isinstance(decryptor, CipherContext) plaintext = decryptor.update(ciphertext) + decryptor.finalize() digest = Hash(SHA256()) digest.update(plaintext) computed_hash = digest.finalize() if not bytes_eq(computed_hash, self._data_hash): raise RuntimeError('Decryption error') return plaintext[plaintext[0]:]
def _shorten_hmac_key(key: bytes) -> bytes: if len(key) > SHA1_BLOCK_SIZE: h = Hash(SHA1(), default_backend()) # nosec h.update(key) key = h.finalize() elif len(key) > HMAC_KEY_SIZE: raise NotSupportedError( "Key lengths > {} bytes not supported".format(HMAC_KEY_SIZE) ) return key
def _build_index(self): index = {} for path in get_git_files(self._repository): if (self._repository / path).is_file(): uuid = str(uuid4()) while index.get(uuid): uuid = str(uuid4()) hasher = Hash(BLAKE2b(64)) with open(self._repository / path, 'rb') as file: hasher.update(file.read()) index[str(path)] = { 'path': str(path), 'uuid': uuid, 'checksum': hasher.finalize().hex() } for path in (self._repository / '.git').glob('**/*'): if path.is_file(): uuid = str(uuid4()) while index.get(uuid): uuid = str(uuid4()) hasher = Hash(BLAKE2b(64)) with open(path, 'rb') as file: hasher.update(file.read()) short_path = path.relative_to(self._repository) index[str(short_path)] = { 'path': str(short_path), 'uuid': uuid, 'checksum': hasher.finalize().hex() } return index
def login(email, password): user = User.query.filter(User.email == email).first() h = Hash(SHA256(), default_backend()) h.update(password.encode('utf-8')) if not user.password == h.finalize(): return None else: return user