def _pairing_one(self): """Send the SRP salt and public key to the client. The SRP verifier is created at this step. """ logger.debug("Pairing [1/5]") self.accessory_handler.setup_srp_verifier() salt, B = self.accessory_handler.srp_verifier.get_challenge() data = tlv.encode(HAP_TLV_TAGS.SEQUENCE_NUM, b'\x02', HAP_TLV_TAGS.SALT, salt, HAP_TLV_TAGS.PUBLIC_KEY, long_to_bytes(B)) self.send_response(200) self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(data, False)
def _pairing_five(self, client_username, client_ltpk, encryption_key): """At that point we know the client has the accessory password and has a valid key pair. Add it as a pair and send a sever proof. Parameters are as for _pairing_four. """ logger.debug("%s: Pairing [5/5]", self.client_address) session_key = self.accessory_handler.srp_verifier.get_session_key() output_key = hap_hkdf(long_to_bytes(session_key), self.PAIRING_5_SALT, self.PAIRING_5_INFO) server_public = self.state.public_key.to_bytes() mac = self.state.mac.encode() material = output_key + mac + server_public private_key = self.state.private_key server_proof = private_key.sign(material) message = tlv.encode( HAP_TLV_TAGS.USERNAME, mac, HAP_TLV_TAGS.PUBLIC_KEY, server_public, HAP_TLV_TAGS.PROOF, server_proof, ) cipher = ChaCha20Poly1305(encryption_key) aead_message = bytes( cipher.encrypt(self.PAIRING_5_NONCE, bytes(message), b"")) client_uuid = uuid.UUID(str(client_username, "utf-8")) should_confirm = self.accessory_handler.pair(client_uuid, client_ltpk) if not should_confirm: self.send_response_with_status( 500, HAP_SERVER_STATUS.INVALID_VALUE_IN_REQUEST) return tlv_data = tlv.encode( HAP_TLV_TAGS.SEQUENCE_NUM, HAP_TLV_STATES.M6, HAP_TLV_TAGS.ENCRYPTED_DATA, aead_message, ) self.response.pairing_changed = True self._send_tlv_pairing_response(tlv_data)
def _pairing_one(self): """Send the SRP salt and public key to the client. The SRP verifier is created at this step. """ logger.debug("%s: Pairing [1/5]", self.client_address) self.accessory_handler.setup_srp_verifier() salt, B = self.accessory_handler.srp_verifier.get_challenge() data = tlv.encode( HAP_TLV_TAGS.SEQUENCE_NUM, HAP_TLV_STATES.M2, HAP_TLV_TAGS.SALT, salt, HAP_TLV_TAGS.PUBLIC_KEY, long_to_bytes(B), ) self._send_tlv_pairing_response(data)
def _pairing_five(self, client_username, client_ltpk, encryption_key): """At that point we know the client has the accessory password and has a valid key pair. Add it as a pair and send a sever proof. Parameters are as for _pairing_four. """ logger.debug("Pairing [5/5]") session_key = self.accessory_handler.srp_verifier.get_session_key() output_key = hap_hkdf(long_to_bytes(session_key), self.PAIRING_5_SALT, self.PAIRING_5_INFO) server_public = self.state.public_key.to_bytes() mac = self.state.mac.encode() material = output_key + mac + server_public private_key = self.state.private_key server_proof = private_key.sign(material) message = tlv.encode(HAP_TLV_TAGS.USERNAME, mac, HAP_TLV_TAGS.PUBLIC_KEY, server_public, HAP_TLV_TAGS.PROOF, server_proof) cipher = ChaCha20Poly1305(encryption_key) aead_message = bytes( cipher.encrypt(self.PAIRING_5_NONCE, bytes(message), b"")) client_uuid = uuid.UUID(str(client_username, "utf-8")) should_confirm = self.accessory_handler.pair(client_uuid, client_ltpk) if not should_confirm: self.send_response(500) self.end_response(b'') return tlv_data = tlv.encode(HAP_TLV_TAGS.SEQUENCE_NUM, b'\x06', HAP_TLV_TAGS.ENCRYPTED_DATA, aead_message) self.send_response(200) self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(tlv_data)
def _pairing_three(self, tlv_objects): """Expand the SRP session key to obtain a new key. Use it to verify and decrypt the recieved data. Continue to step four. @param tlv_objects: The TLV data received from the client. @type tlv_object: dict """ logger.debug("Pairing [3/5]") encrypted_data = tlv_objects[HAP_TLV_TAGS.ENCRYPTED_DATA] session_key = self.accessory_handler.srp_verifier.get_session_key() hkdf_enc_key = hap_hkdf(long_to_bytes(session_key), self.PAIRING_3_SALT, self.PAIRING_3_INFO) cipher = ChaCha20Poly1305(hkdf_enc_key) decrypted_data = cipher.decrypt(self.PAIRING_3_NONCE, bytes(encrypted_data), b"") assert decrypted_data is not None dec_tlv_objects = tlv.decode(bytes(decrypted_data)) client_username = dec_tlv_objects[HAP_TLV_TAGS.USERNAME] client_ltpk = dec_tlv_objects[HAP_TLV_TAGS.PUBLIC_KEY] client_proof = dec_tlv_objects[HAP_TLV_TAGS.PROOF] self._pairing_four(client_username, client_ltpk, client_proof, hkdf_enc_key)