def _seqno5_pairing(self, _): session_key = hkdf_expand('Pair-Setup-Encrypt-Salt', 'Pair-Setup-Encrypt-Info', binascii.unhexlify(self.session.key)) acc_device_x = hkdf_expand('Pair-Setup-Accessory-Sign-Salt', 'Pair-Setup-Accessory-Sign-Info', binascii.unhexlify(self.session.key)) device_info = acc_device_x + self.unique_id + self.keys.auth_pub signature = self.keys.sign.sign(device_info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.unique_id, tlv8.TLV_PUBLIC_KEY: self.keys.auth_pub, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce='PS-Msg06'.encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x06', tlv8.TLV_ENCRYPTED_DATA: encrypted, }) self.has_paired = True self.delegate.send(msg)
def _seqno5_pairing(self, _): session_key = hkdf_expand( "Pair-Setup-Encrypt-Salt", "Pair-Setup-Encrypt-Info", binascii.unhexlify(self.session.key), ) acc_device_x = hkdf_expand( "Pair-Setup-Accessory-Sign-Salt", "Pair-Setup-Accessory-Sign-Info", binascii.unhexlify(self.session.key), ) device_info = acc_device_x + self.unique_id + self.keys.auth_pub signature = self.keys.sign.sign(device_info) tlv = write_tlv({ TlvValue.Identifier: self.unique_id, TlvValue.PublicKey: self.keys.auth_pub, TlvValue.Signature: signature, }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce="PS-Msg06".encode()) msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x06", TlvValue.EncryptedData: encrypted }) self.has_paired = True self.delegate.send(msg)
def step4(self, encrypted_data): """Last pairing step.""" chacha = chacha20.Chacha20Cipher(self._session_key, self._session_key) decrypted_tlv_bytes = chacha.decrypt(encrypted_data, nounce="PS-Msg06".encode()) if not decrypted_tlv_bytes: raise exceptions.AuthenticationError("data decrypt failed") decrypted_tlv = hap_tlv8.read_tlv(decrypted_tlv_bytes) _LOGGER.debug("PS-Msg06: %s", decrypted_tlv) atv_identifier = decrypted_tlv[hap_tlv8.TlvValue.Identifier] atv_signature = decrypted_tlv[hap_tlv8.TlvValue.Signature] atv_pub_key = decrypted_tlv[hap_tlv8.TlvValue.PublicKey] log_binary( _LOGGER, "Device", Identifier=atv_identifier, Signature=atv_signature, Public=atv_pub_key, ) # TODO: verify signature here return Credentials(atv_pub_key, self._auth_private, atv_identifier, self.pairing_id)
def step3(self): """Third pairing step.""" ios_device_x = hkdf_expand( "Pair-Setup-Controller-Sign-Salt", "Pair-Setup-Controller-Sign-Info", binascii.unhexlify(self._session.key), ) self._session_key = hkdf_expand( "Pair-Setup-Encrypt-Salt", "Pair-Setup-Encrypt-Info", binascii.unhexlify(self._session.key), ) device_info = ios_device_x + self.pairing_id + self._auth_public device_signature = self._signing_key.sign(device_info) tlv = tlv8.write_tlv( { tlv8.TLV_IDENTIFIER: self.pairing_id, tlv8.TLV_PUBLIC_KEY: self._auth_public, tlv8.TLV_SIGNATURE: device_signature, } ) chacha = chacha20.Chacha20Cipher(self._session_key, self._session_key) encrypted_data = chacha.encrypt(tlv, nounce="PS-Msg05".encode()) log_binary(_LOGGER, "Data", Encrypted=encrypted_data) return encrypted_data
def step3(self): """Third pairing step.""" ios_device_x = hkdf_expand( "Pair-Setup-Controller-Sign-Salt", "Pair-Setup-Controller-Sign-Info", binascii.unhexlify(self._session.key), ) self._session_key = hkdf_expand( "Pair-Setup-Encrypt-Salt", "Pair-Setup-Encrypt-Info", binascii.unhexlify(self._session.key), ) device_info = ios_device_x + self.pairing_id + self._auth_public device_signature = self._signing_key.sign(device_info) tlv = hap_tlv8.write_tlv({ hap_tlv8.TlvValue.Identifier: self.pairing_id, hap_tlv8.TlvValue.PublicKey: self._auth_public, hap_tlv8.TlvValue.Signature: device_signature, }) chacha = chacha20.Chacha20Cipher(self._session_key, self._session_key) encrypted_data = chacha.encrypt(tlv, nounce="PS-Msg05".encode()) log_binary(_LOGGER, "Data", Encrypted=encrypted_data) return encrypted_data
def verify1(self, credentials, session_pub_key, encrypted): """First verification step.""" # No additional hashing used self._shared = self._verify_private.get_shared_key( curve25519.Public(session_pub_key), hashfunc=lambda x: x) session_key = hkdf_expand('Pair-Verify-Encrypt-Salt', 'Pair-Verify-Encrypt-Info', self._shared) chacha = chacha20.Chacha20Cipher(session_key, session_key) decrypted_tlv = tlv8.read_tlv( chacha.decrypt(encrypted, nounce='PV-Msg02'.encode())) identifier = decrypted_tlv[tlv8.TLV_IDENTIFIER] signature = decrypted_tlv[tlv8.TLV_SIGNATURE] if identifier != credentials.atv_id: raise Exception('incorrect device response') # TODO: new exception info = session_pub_key + \ bytes(identifier) + self._verify_public.serialize() ltpk = VerifyingKey(bytes(credentials.ltpk)) ltpk.verify(bytes(signature), bytes(info)) # throws if no match device_info = self._verify_public.serialize() + \ credentials.client_id + session_pub_key device_signature = SigningKey(credentials.ltsk).sign(device_info) tlv = tlv8.write_tlv({tlv8.TLV_IDENTIFIER: credentials.client_id, tlv8.TLV_SIGNATURE: device_signature}) return chacha.encrypt(tlv, nounce='PV-Msg03'.encode())
def step4(self, encrypted_data): """Last pairing step.""" chacha = chacha20.Chacha20Cipher(self._session_key, self._session_key) decrypted_tlv_bytes = chacha.decrypt( encrypted_data, nounce='PS-Msg06'.encode()) if not decrypted_tlv_bytes: raise exceptions.AuthenticationError('data decrypt failed') decrypted_tlv = tlv8.read_tlv(decrypted_tlv_bytes) _LOGGER.debug('PS-Msg06: %s', decrypted_tlv) atv_identifier = decrypted_tlv[tlv8.TLV_IDENTIFIER] atv_signature = decrypted_tlv[tlv8.TLV_SIGNATURE] atv_pub_key = decrypted_tlv[tlv8.TLV_PUBLIC_KEY] log_binary(_LOGGER, 'Device', Identifier=atv_identifier, Signature=atv_signature, Public=atv_pub_key) # TODO: verify signature here return Credentials(atv_pub_key, self._signing_key.to_seed(), atv_identifier, self.pairing_id)
def _seqno_1(self, pairing_data): if self.has_paired: server_pub_key = self._verify_public.serialize() client_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY] self._shared = self._verify_private.get_shared_key( curve25519.Public(client_pub_key), hashfunc=lambda x: x) session_key = hkdf_expand('Pair-Verify-Encrypt-Salt', 'Pair-Verify-Encrypt-Info', self._shared) info = server_pub_key + self.atv_device_id + client_pub_key signature = SigningKey(self._signing_key.to_seed()).sign(info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.atv_device_id, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce='PV-Msg02'.encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x02', tlv8.TLV_PUBLIC_KEY: server_pub_key, tlv8.TLV_ENCRYPTED_DATA: encrypted }) self.output_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Write-Encryption-Key', self._shared) self.input_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Read-Encryption-Key', self._shared) log_binary(_LOGGER, 'Keys', Output=self.output_key, Input=self.input_key) else: msg = messages.crypto_pairing({ tlv8.TLV_SALT: binascii.unhexlify(self.salt), tlv8.TLV_PUBLIC_KEY: binascii.unhexlify(self._session.public), tlv8.TLV_SEQ_NO: b'\x02' }) self._send(msg)
def verify1(self, credentials, session_pub_key, encrypted): """First verification step.""" self._shared = self._verify_private.exchange( X25519PublicKey.from_public_bytes(session_pub_key) ) session_key = hkdf_expand( "Pair-Verify-Encrypt-Salt", "Pair-Verify-Encrypt-Info", self._shared ) chacha = chacha20.Chacha20Cipher(session_key, session_key) decrypted_tlv = tlv8.read_tlv( chacha.decrypt(encrypted, nounce="PV-Msg02".encode()) ) identifier = decrypted_tlv[tlv8.TLV_IDENTIFIER] signature = decrypted_tlv[tlv8.TLV_SIGNATURE] if identifier != credentials.atv_id: raise exceptions.AuthenticationError("incorrect device response") info = session_pub_key + bytes(identifier) + self._public_bytes ltpk = Ed25519PublicKey.from_public_bytes(bytes(credentials.ltpk)) try: ltpk.verify(bytes(signature), bytes(info)) except InvalidSignature as ex: raise exceptions.AuthenticationError("signature error") from ex device_info = self._public_bytes + credentials.client_id + session_pub_key device_signature = Ed25519PrivateKey.from_private_bytes(credentials.ltsk).sign( device_info ) tlv = tlv8.write_tlv( { tlv8.TLV_IDENTIFIER: credentials.client_id, tlv8.TLV_SIGNATURE: device_signature, } ) return chacha.encrypt(tlv, nounce="PV-Msg03".encode())
def _seqno_3(self, pairing_data): if self.has_paired: self._send(messages.crypto_pairing({tlv8.TLV_SEQ_NO: b'\x04'})) self.chacha = chacha20.Chacha20Cipher(self.input_key, self.output_key) else: pubkey = binascii.hexlify( pairing_data[tlv8.TLV_PUBLIC_KEY]).decode() self._session.process(pubkey, self.salt) proof = binascii.unhexlify(self._session.key_proof_hash) assert self._session.verify_proof( binascii.hexlify(pairing_data[tlv8.TLV_PROOF])) msg = messages.crypto_pairing({ tlv8.TLV_PROOF: proof, tlv8.TLV_SEQ_NO: b'\x04' }) self._send(msg)
def _seqno1_paired(self, pairing_data): server_pub_key = self.keys.verify_pub.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) client_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY] shared_key = self.keys.verify.exchange( X25519PublicKey.from_public_bytes(client_pub_key)) session_key = hkdf_expand("Pair-Verify-Encrypt-Salt", "Pair-Verify-Encrypt-Info", shared_key) info = server_pub_key + self.unique_id + client_pub_key signature = self.keys.sign.sign(info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.unique_id, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce="PV-Msg02".encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b"\x02", tlv8.TLV_PUBLIC_KEY: server_pub_key, tlv8.TLV_ENCRYPTED_DATA: encrypted, }) self.output_key = hkdf_expand("MediaRemote-Salt", "MediaRemote-Write-Encryption-Key", shared_key) self.input_key = hkdf_expand("MediaRemote-Salt", "MediaRemote-Read-Encryption-Key", shared_key) log_binary(_LOGGER, "Keys", Output=self.output_key, Input=self.input_key) self.delegate.send(msg)
def _seqno1_paired(self, pairing_data): server_pub_key = self.keys.verify_pub.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) client_pub_key = pairing_data[TlvValue.PublicKey] shared_key = self.keys.verify.exchange( X25519PublicKey.from_public_bytes(client_pub_key)) session_key = hkdf_expand("Pair-Verify-Encrypt-Salt", "Pair-Verify-Encrypt-Info", shared_key) info = server_pub_key + self.unique_id + client_pub_key signature = self.keys.sign.sign(info) tlv = write_tlv({ TlvValue.Identifier: self.unique_id, TlvValue.Signature: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce="PV-Msg02".encode()) msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x02", TlvValue.PublicKey: server_pub_key, TlvValue.EncryptedData: encrypted, }) self.output_key = hkdf_expand("MediaRemote-Salt", "MediaRemote-Write-Encryption-Key", shared_key) self.input_key = hkdf_expand("MediaRemote-Salt", "MediaRemote-Read-Encryption-Key", shared_key) log_binary(_LOGGER, "Keys", Output=self.output_key, Input=self.input_key) self.delegate.send(msg)
def _seqno1_paired(self, pairing_data): server_pub_key = self.keys.verify_pub.serialize() client_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY] shared_key = self.keys.verify.get_shared_key( curve25519.Public(client_pub_key), hashfunc=lambda x: x) session_key = hkdf_expand('Pair-Verify-Encrypt-Salt', 'Pair-Verify-Encrypt-Info', shared_key) info = server_pub_key + self.unique_id + client_pub_key signature = self.keys.sign.sign(info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.unique_id, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce='PV-Msg02'.encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x02', tlv8.TLV_PUBLIC_KEY: server_pub_key, tlv8.TLV_ENCRYPTED_DATA: encrypted }) self.output_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Write-Encryption-Key', shared_key) self.input_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Read-Encryption-Key', shared_key) log_binary(_LOGGER, 'Keys', Output=self.output_key, Input=self.input_key) self.delegate.send(msg)
def enable_encryption(self, input_key, output_key): """Enable encryption with specified keys.""" self.chacha = chacha20.Chacha20Cipher(input_key, output_key)
def enable_encryption(self, input_key, output_key): """Enable encryption with specified keys.""" self.chacha = chacha20.Chacha20Cipher(input_key, output_key) self.state.has_authenticated = True