async def verify_credentials(self): """Verify credentials with device.""" _, public_key = self.srp.initialize() msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x01", TlvValue.PublicKey: public_key }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) resp = _get_pairing_data(resp) session_pub_key = resp[TlvValue.PublicKey] encrypted = resp[TlvValue.EncryptedData] log_binary(_LOGGER, "Device", Public=self.credentials.ltpk, Encrypted=encrypted) encrypted_data = self.srp.verify1(self.credentials, session_pub_key, encrypted) msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x03", TlvValue.EncryptedData: encrypted_data }) await self.protocol.send_and_receive(msg, generate_identifier=False) # TODO: check status code self._output_key, self._input_key = self.srp.verify2()
async def finish_pairing(self, pin): """Finish pairing process.""" self.srp.step1(pin) pub_key, proof = self.srp.step2(self._atv_pub_key, self._atv_salt) msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x03", TlvValue.PublicKey: pub_key, TlvValue.Proof: proof, }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) atv_proof = pairing_data[TlvValue.Proof] log_binary(_LOGGER, "Device", Proof=atv_proof) encrypted_data = self.srp.step3() msg = messages.crypto_pairing({ TlvValue.SeqNo: b"\x05", TlvValue.EncryptedData: encrypted_data }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) encrypted_data = pairing_data[TlvValue.EncryptedData] return self.srp.step4(encrypted_data)
async def verify_credentials(self): """Verify credentials with device.""" _, public_key = self.srp.initialize() msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x01', tlv8.TLV_PUBLIC_KEY: public_key }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) resp = _get_pairing_data(resp) session_pub_key = resp[tlv8.TLV_PUBLIC_KEY] encrypted = resp[tlv8.TLV_ENCRYPTED_DATA] log_binary(_LOGGER, 'Device', Public=self.credentials.ltpk, Encrypted=encrypted) encrypted_data = self.srp.verify1(self.credentials, session_pub_key, encrypted) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x03', tlv8.TLV_ENCRYPTED_DATA: encrypted_data }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) # TODO: check status code self._output_key, self._input_key = self.srp.verify2()
async def finish_pairing(self, pin): """Finish pairing process.""" self.srp.step1(pin) pub_key, proof = self.srp.step2(self._atv_pub_key, self._atv_salt) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x03', tlv8.TLV_PUBLIC_KEY: pub_key, tlv8.TLV_PROOF: proof }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) atv_proof = pairing_data[tlv8.TLV_PROOF] log_binary(_LOGGER, 'Device', Proof=atv_proof) encrypted_data = self.srp.step3() msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x05', tlv8.TLV_ENCRYPTED_DATA: encrypted_data }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) encrypted_data = pairing_data[tlv8.TLV_ENCRYPTED_DATA] return self.srp.step4(encrypted_data)
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)
async def start_pairing(self): """Start pairing procedure.""" self.srp.initialize() await self.protocol.start(skip_initial_messages=True) msg = messages.crypto_pairing( { tlv8.TLV_METHOD: b'\x00', tlv8.TLV_SEQ_NO: b'\x01' }, is_pairing=True) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) if tlv8.TLV_BACK_OFF in pairing_data: time = int.from_bytes(pairing_data[tlv8.TLV_BACK_OFF], byteorder='little') raise exceptions.BackOffError( 'please wait {0}s before trying again'.format(time)) self._atv_salt = pairing_data[tlv8.TLV_SALT] self._atv_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY]
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 _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_pairing(self, pairing_data): msg = messages.crypto_pairing({ TlvValue.Salt: binascii.unhexlify(self.salt), TlvValue.PublicKey: binascii.unhexlify(self.session.public), TlvValue.SeqNo: b"\x02", }) self.delegate.send(msg)
def _seqno1_pairing(self, pairing_data): 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.delegate.send(msg)
def _seqno3_pairing(self, pairing_data): pubkey = binascii.hexlify(pairing_data[tlv8.TLV_PUBLIC_KEY]).decode() self.session.process(pubkey, self.salt) proof = binascii.unhexlify(self.session.key_proof_hash) if 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' }) else: msg = messages.crypto_pairing({ tlv8.TLV_ERROR: tlv8.ERROR_AUTHENTICATION.encode(), tlv8.TLV_SEQ_NO: b'\x04' }) self.delegate.send(msg)
def _seqno3_pairing(self, pairing_data): pubkey = binascii.hexlify(pairing_data[TlvValue.PublicKey]).decode() self.session.process(pubkey, self.salt) proof = binascii.unhexlify(self.session.key_proof_hash) if self.session.verify_proof( binascii.hexlify(pairing_data[TlvValue.Proof])): msg = messages.crypto_pairing({ TlvValue.Proof: proof, TlvValue.SeqNo: b"\x04" }) else: msg = messages.crypto_pairing({ TlvValue.Error: bytes([ErrorCode.Authentication]), TlvValue.SeqNo: b"\x04", }) self.delegate.send(msg)
async def start_pairing(self): """Start pairing procedure.""" self.srp.initialize() await self.protocol.start(skip_initial_messages=True) msg = messages.crypto_pairing( { TlvValue.Method: b"\x00", TlvValue.SeqNo: b"\x01" }, is_pairing=True, ) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) self._atv_salt = pairing_data[TlvValue.Salt] self._atv_pub_key = pairing_data[TlvValue.PublicKey]
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)
async def start_pairing(self): """Start pairing procedure.""" self.srp.initialize() msg = messages.crypto_pairing({ tlv8.TLV_METHOD: b'\x00', tlv8.TLV_SEQ_NO: b'\x01' }) resp = await self.protocol.send_and_receive(msg, generate_identifier=False) pairing_data = _get_pairing_data(resp) if tlv8.TLV_BACK_OFF in pairing_data: time = int.from_bytes(pairing_data[tlv8.TLV_BACK_OFF], byteorder='big') raise Exception('back off {0}s'.format(time)) self._atv_salt = pairing_data[tlv8.TLV_SALT] self._atv_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY]
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 _seqno3_paired(self, pairing_data): self.delegate.send(messages.crypto_pairing({tlv8.TLV_SEQ_NO: b'\x04'})) self.delegate.enable_encryption(self.input_key, self.output_key)
def _seqno3_paired(self, pairing_data): self.delegate.send(messages.crypto_pairing({TlvValue.SeqNo: b"\x04"})) self.delegate.enable_encryption(self.input_key, self.output_key)