Beispiel #1
0
    async def finish_pairing(self, username: str, pin_code: int) -> HapCredentials:
        """Finish pairing process."""
        self.srp.step1(pin_code)

        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)
Beispiel #2
0
    def _m5_setup(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.send_to_client(msg)
Beispiel #3
0
    def _m1_setup(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.send_to_client(msg)
Beispiel #4
0
    def _m3_setup(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.send_to_client(msg)
Beispiel #5
0
    async def verify_credentials(self) -> bool:
        """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

        return True
Beispiel #6
0
    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]
Beispiel #7
0
    def _m1_verify(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.send_to_client(msg)
Beispiel #8
0
 def _m3_verify(self, pairing_data):
     self.send_to_client(messages.crypto_pairing({TlvValue.SeqNo: b"\x04"}))
     self.enable_encryption(self.input_key, self.output_key)