Example #1
0
 def test_to_string_for_dict(self):
     example = {1: 'hello'}
     res = TLV.to_string(example)
     self.assertEqual(res, '{\n  1: (5 bytes) hello\n}\n')
     example = {1: 'hello', 2: 'world'}
     res = TLV.to_string(example)
     self.assertEqual(res,
                      '{\n  1: (5 bytes) hello\n  2: (5 bytes) world\n}\n')
Example #2
0
    def write_http(request, expected):
        logging.debug('write message: %s',
                      TLV.to_string(TLV.decode_bytes(request)))
        headers = {'Content-Type': 'application/pairing+tlv8'}

        connection.request('POST', '/pair-verify', request, headers)
        resp = connection.getresponse()
        response_tlv = TLV.decode_bytes(resp.read(), expected)
        logging.debug('response: %s', TLV.to_string(response_tlv))
        return response_tlv
Example #3
0
 def write_http(request, expected):
     logging.debug('write message: %s', TLV.to_string(TLV.decode_bytes(request)))
     connection.putrequest('POST', '/pair-verify', skip_accept_encoding=True)
     connection.putheader('Content-Type', 'application/pairing+tlv8')
     connection.putheader('Content-Length', len(request))
     connection.endheaders(request)
     resp = connection.getresponse()
     response_tlv = TLV.decode_bytes(resp.read(), expected)
     logging.debug('response: %s', TLV.to_string(response_tlv))
     return response_tlv
Example #4
0
    def write(request, expected):
        # TODO document me
        body = TLV.encode_list(request)
        logger.debug('entering write function %s',
                     TLV.to_string(TLV.decode_bytes(body)))
        request_tlv = TLV.encode_list([(TLV.kTLVHAPParamParamReturnResponse,
                                        bytearray(b'\x01')),
                                       (TLV.kTLVHAPParamValue, body)])
        transaction_id = random.randrange(0, 255)
        data = bytearray([0x00, HapBleOpCodes.CHAR_WRITE, transaction_id])
        data.extend(characteristic_id.to_bytes(length=2, byteorder='little'))
        data.extend(len(request_tlv).to_bytes(length=2, byteorder='little'))
        data.extend(request_tlv)
        logger.debug('sent %s', bytes(data).hex())
        characteristic.write_value(value=data)
        data = []
        while len(data) == 0:
            time.sleep(1)
            logger.debug('reading characteristic')
            data = characteristic.read_value()
        resp_data = [b for b in data]

        expected_length = int.from_bytes(bytes(resp_data[3:5]),
                                         byteorder='little')
        logger.debug(
            'control field: {c:x}, tid: {t:x}, status: {s:x}, length: {length}'
            .format(c=resp_data[0],
                    t=resp_data[1],
                    s=resp_data[2],
                    length=expected_length))
        while len(resp_data[3:]) < expected_length:
            time.sleep(1)
            logger.debug('reading characteristic')
            data = characteristic.read_value()
            resp_data.extend([b for b in data])
            logger.debug('data %s of %s', len(resp_data[3:]), expected_length)

        logger.debug('received %s', bytes(resp_data).hex())
        logger.debug('decode %s', bytes(resp_data[5:]).hex())
        resp_tlv = TLV.decode_bytes(bytes([int(a) for a in resp_data[5:]]),
                                    expected=[TLV.kTLVHAPParamValue])
        result = TLV.decode_bytes(resp_tlv[0][1], expected)
        logger.debug('leaving write function %s', TLV.to_string(result))
        return result
Example #5
0
 def test_to_string_for_list(self):
     example = [
         (
             1,
             'hello',
         ),
     ]
     res = TLV.to_string(example)
     self.assertEqual(res, '[\n  1: (5 bytes) hello\n]\n')
     example = [
         (
             1,
             'hello',
         ),
         (
             2,
             'world',
         ),
     ]
     res = TLV.to_string(example)
     self.assertEqual(res,
                      '[\n  1: (5 bytes) hello\n  2: (5 bytes) world\n]\n')
Example #6
0
 def test_to_string_for_list_bytearray(self):
     example = [[1, bytearray([0x42, 0x23])]]
     res = TLV.to_string(example)
     self.assertEqual(res, '[\n  1: (2 bytes) 0x4223\n]\n')
Example #7
0
 def test_to_string_for_dict_bytearray(self):
     example = {1: bytearray([0x42, 0x23])}
     res = TLV.to_string(example)
     self.assertEqual(res, '{\n  1: (2 bytes) 0x4223\n}\n')
Example #8
0
    def request(self, feature_char, feature_char_id, op, body=None):
        transaction_id = random.randrange(0, 255)

        data = bytearray([0x00, op, transaction_id])
        data.extend(feature_char_id.to_bytes(length=2, byteorder='little'))

        if body:
            logger.debug('body: %s', body)
            data.extend(body)

        logger.debug('data: %s', data)

        cnt_bytes = self.c2a_counter.to_bytes(8, byteorder='little')
        cipher_and_mac = chacha20_aead_encrypt(bytes(), self.c2a_key, cnt_bytes, bytes([0, 0, 0, 0]), data)
        cipher_and_mac[0].extend(cipher_and_mac[1])
        data = cipher_and_mac[0]
        logger.debug('cipher and mac %s', cipher_and_mac[0].hex())

        result = feature_char.write_value(value=data)
        logger.debug('write resulted in: %s', result)

        self.c2a_counter += 1

        data = []
        while not data or len(data) == 0:
            time.sleep(1)
            logger.debug('reading characteristic')
            data = feature_char.read_value()
            if not data and not self.device.is_connected():
                raise AccessoryDisconnectedError('Characteristic read failed')

        resp_data = bytearray([b for b in data])
        logger.debug('read: %s', bytearray(resp_data).hex())

        data = chacha20_aead_decrypt(bytes(), self.a2c_key, self.a2c_counter.to_bytes(8, byteorder='little'),
                                     bytes([0, 0, 0, 0]), resp_data)

        logger.debug('decrypted: %s', bytearray(data).hex())

        if not data:
            return {}

        # parse header and check stuff
        logger.debug('parse sig read response %s', bytes([int(a) for a in data]).hex())

        # handle the header data
        cf = data[0]
        logger.debug('control field %d', cf)
        tid = data[1]
        logger.debug('transaction id %d (expected was %d)', tid, transaction_id)
        status = data[2]
        logger.debug('status code %d (%s)', status, HapBleStatusCodes[status])
        assert cf == 0x02
        assert tid == transaction_id

        if status != HapBleStatusCodes.SUCCESS:
            raise RequestRejected(status, HapBleStatusCodes[status])

        self.a2c_counter += 1

        # get body length
        length = int.from_bytes(data[3:5], byteorder='little')
        logger.debug('expected body length %d (got %d)', length, len(data[5:]))

        # parse tlvs and analyse information
        tlv = TLV.decode_bytes(data[5:])
        logger.debug('received TLV: %s', TLV.to_string(tlv))
        return dict(tlv)