示例#1
0
def _get_pairing_data(resp):
    pairing_message = CryptoPairingMessage.cryptoPairingMessage
    tlv = tlv8.read_tlv(resp.Extensions[pairing_message].pairingData)
    if tlv8.TLV_ERROR in tlv:
        error = int.from_bytes(tlv[tlv8.TLV_ERROR], byteorder="little")
        raise exceptions.AuthenticationError("got error: " + str(error))
    return tlv
示例#2
0
    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._auth_private, atv_identifier, self.pairing_id
        )
示例#3
0
    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())
示例#4
0
    def handle_crypto_pairing(self, message, inner):
        """Handle incoming crypto pairing message."""
        _LOGGER.debug('Received crypto pairing message')
        pairing_data = tlv8.read_tlv(inner.pairingData)
        seqno = pairing_data[tlv8.TLV_SEQ_NO][0]

        # Work-around for now to support "tries" to auth before pairing
        if seqno == 1:
            if tlv8.TLV_PUBLIC_KEY in pairing_data:
                self.has_paired = True
            elif tlv8.TLV_METHOD in pairing_data:
                self.has_paired = False

        suffix = 'paired' if self.has_paired else 'pairing'
        method = '_seqno{0}_{1}'.format(seqno, suffix)
        getattr(self, method)(pairing_data)
示例#5
0
    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())
示例#6
0
    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 Exception('data decrypt failed')  # TODO: new exception
        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)
示例#7
0
 def test_read_key_larger_than_255_bytes(self):
     self.assertEqual(read_tlv(LARGE_KEY_OUT), LARGE_KEY_IN)
示例#8
0
 def test_read_two_keys(self):
     self.assertEqual(read_tlv(DOUBLE_KEY_OUT), DOUBLE_KEY_IN)
示例#9
0
 def test_read_single_key(self):
     self.assertEqual(read_tlv(SINGLE_KEY_OUT), SINGLE_KEY_IN)
示例#10
0
def _get_pairing_data(resp):
    pairing_message = CryptoPairingMessage.cryptoPairingMessage
    return tlv8.read_tlv(resp.Extensions[pairing_message].pairingData)
示例#11
0
 def handle_crypto_pairing(self, message, _):
     """Handle incoming crypto pairing message."""
     _LOGGER.debug('Received crypto pairing message')
     pairing_data = tlv8.read_tlv(message.inner().pairingData)
     seqno = pairing_data[tlv8.TLV_SEQ_NO][0]
     getattr(self, "_seqno_" + str(seqno))(pairing_data)