Ejemplo n.º 1
0
    def parse(
        cls,
        data: Union[bytes, bytearray],
        key: bytes,
        d2key: bytes,
        session_key: bytes,
    ) -> "IncomingPacket":
        if not isinstance(data, Packet):
            data = Packet(data)

        packet_type, encrypt_type, flag3, uin, payload = (
            data.start().uint32().uint8().uint8().string(4,
                                                         4).remain().execute())

        if packet_type not in [0xA, 0xB]:
            raise ValueError(
                f"Invalid packet type. Expected 0xA / 0xB, got {packet_type}.")
        if flag3 != 0:
            raise ValueError(f"Invalid flag3. Expected 0, got {flag3}.")

        try:
            uin = int(uin)
        except ValueError:
            uin = 0

        if encrypt_type == 0:
            pass
        elif encrypt_type == 1:
            payload = Packet(qqtea_decrypt(bytes(payload), d2key))
        elif encrypt_type == 2:
            payload = Packet(qqtea_decrypt(bytes(payload), bytes(16)))
        else:
            raise ValueError(
                f"Invalid encrypt type. Expected 0 / 1 / 2, got {encrypt_type}."
            )

        if not payload:
            raise ValueError(f"Data cannot be none.")

        # offset = 0
        # sso_head_length = payload.read_int32(offset) - 4
        # offset += 4
        offset = 4
        sso_frame = payload[offset:]

        return cls.parse_sso_frame(sso_frame,
                                   encrypt_type,
                                   key,
                                   session_key,
                                   uin=uin)
Ejemplo n.º 2
0
def test_qqtea_mixed_n(n):
    seed(114514)
    for i in range(32):
        key, text = randbytes(16), randbytes(n)

        cipher_text = qqtea_encrypt(text, key)
        assert pyqqtea_decrypt(cipher_text,
                               key) == qqtea_decrypt(cipher_text,
                                                     key), f"in round {i}"

        cipher_text = pyqqtea_encrypt(text, key)
        assert pyqqtea_decrypt(cipher_text,
                               key) == qqtea_decrypt(cipher_text,
                                                     key), f"in round {i}"
Ejemplo n.º 3
0
    def t119(cls, data: bytes) -> Dict[int, Any]:
        """Tea decrypt tlv 119 data.

        Tlv list:
            * tlv 149: error message (optional).
            * tlv 543:
            * tlv 130: further decode.
            * tlv 113: further decode.
            * tlv 528:
            * tlv 530:
            * tlv 10d: tgt key.
            * tlv 10e: st key.
            * tlv 10a: tgt.
            * tlv 114: st.
            * tlv 11a: further decode.
            * tlv 118: main display name.
            * tlv 103: stwx web sig.
            * tlv 108: ksid.
            * tlv 102:
            * tlv 10b:
            * tlv 11c: ls key.
            * tlv 120: skey.
            * tlv 121: sig64.
            * tlv 125: further decode.
            * tlv 186: further decode.
            * tlv 537: login extra data.
            * tlv 169:
            * tlv 167:
            * tlv 10c:
            * tlv 106: encrypted a1.
            * tlv 16a: no pic sig.
            * tlv 531: further decode.
            * tlv 136: vkey.
            * tlv 132: access token.
            * tlv 143: d2.
            * tlv 305: d2 key.
            * tlv 164: sid.
            * tlv 171: aq sig.
            * tlv 512: ps key.
            * tlv 16d: super key.
            * tlv 199: further decode.
            * tlv 200: further decode.
            * tlv 203: pfkey.
            * tlv 317: da2.
            * tlv 133: wt session ticket.
            * tlv 134: wt session ticket key.
            * tlv 322: device token.
            * tlv 11f: futher decode. change time and tk_pri.
            * tlv 138: further decode. a2, lskey, skey, vkey, a8, stweb, d2, sid change time.
            * tlv 11d: further decode. st and stkey.

        Note:
            Source: oicq.wlogin_sdk.request.oicq_request.d
        """
        data = qqtea_decrypt(data, DEVICE.tgtgt)
        result = cls.decode(data, offset=2)
        return result
Ejemplo n.º 4
0
    def parse_oicq_body(cls, data: Union[bytes, bytearray], key: bytes,
                        session_key: bytes) -> bytes:
        """Parse incoming OICQ packet.

        Note:
            Source: oicq.wlogin_sdk.request.oicq_request.b

        Args:
            data (Union[bytes, Packet]): OICQ data.
            key (bytes): Random key.
            session_key (bytes): Siginfo wt_session_ticket_key.

        Raises:
            ValueError: Flag error or unknown encrypt type.

        Returns:
            bytes: Decode data.
        """
        if not isinstance(data, Packet):
            data = Packet(data)

        flag, encrypt_type, body = (data.start().uint8().offset(
            12).uint16().offset(1).remain().execute())

        if flag != 2:
            raise ValueError(
                f"Invalid OICQ response flag. Expected 2, got {flag}.")

        body = body[:-1]
        if encrypt_type == 0:
            try:
                return qqtea_decrypt(bytes(body), ECDH.share_key)
            except Exception:
                return qqtea_decrypt(bytes(body), key)
        elif encrypt_type == 3:
            return qqtea_decrypt(bytes(body), session_key)
        elif encrypt_type == 4:
            # seems not used
            # data = qqtea_decrypt(bytes(body), ECDH.share_key)
            # ...
            raise NotImplementedError
        else:
            raise ValueError(f"Unknown encrypt type: {encrypt_type}")
Ejemplo n.º 5
0
async def get_sso_list() -> SsoServerResponse:
    """Do sso server list request and return the response.

    Note:
        Source: com.tencent.mobileqq.msf.core.a.f.run

    Returns:
        SsoServerResponse: Sso server list response

    Raises:
        SsoServerException: Get sso server list failed.
    """
    device = get_device()
    protocol = get_protocol()
    key = bytes([
        0xF0,
        0x44,
        0x1F,
        0x5F,
        0xF4,
        0x2D,
        0xA5,
        0x8F,
        0xDC,
        0xF7,
        0x94,
        0x9A,
        0xBA,
        0x62,
        0xD4,
        0x11,
    ])
    payload = SsoServerRequest.to_bytes(
        0, SsoServerRequest(app_id=protocol.app_id, imei=device.imei))
    req_packet = RequestPacketVersion3(
        servant_name="HttpServerListReq",
        func_name="HttpServerListReq",
        data=types.MAP(
            {types.STRING("HttpServerListReq"): types.BYTES(payload)}),
    ).encode(with_length=True)
    buffer: bytes = qqtea_encrypt(req_packet, key)
    async with connect("configsvr.msf.3g.qq.com", 443, ssl=True) as conn:
        query = (b"POST /configsvr/serverlist.jsp HTTP/1.1\r\n"
                 b"Host: configsvr.msf.3g.qq.com\r\n"
                 b"User-Agent: QQ/8.4.1.2703 CFNetwork/1126\r\n"
                 b"Net-Type: Wifi\r\n"
                 b"Accept: */*\r\n"
                 b"Connection: close\r\n"
                 b"Content-Type: application/octet-stream\r\n"
                 b"Content-Length: " + str(len(buffer)).encode() + b"\r\n"
                 b"\r\n" + buffer)
        conn.write(query)
        conn.write_eof()
        resp_bytes = await conn.read_all()
        response = http.client.HTTPResponse(
            _FakeSocket(resp_bytes)  # type: ignore
        )
        response.begin()

    if response.status != 200:
        raise SsoServerException(
            f"Get sso server list failed with response code {response.status}")
    data: bytes = qqtea_decrypt(response.read(), key)
    resp_packet = RequestPacketVersion3.decode(data)
    server_info = SsoServerResponse.decode(
        resp_packet.data["HttpServerListRes"][1:-1]  # type: ignore
    )
    return server_info
Ejemplo n.º 6
0
 def func(key, cipher_text):
     qqtea_decrypt(cipher_text, key)
Ejemplo n.º 7
0
async def handle_oicq_response(client: "Client",
                               packet: IncomingPacket) -> OICQResponse:
    response = OICQResponse.decode_response(
        packet.uin,
        packet.seq,
        packet.ret_code,
        packet.command_name,
        packet.data,
    )
    if not isinstance(response, UnknownLoginStatus):
        return response

    if response.t402:
        client._siginfo.dpwd = ("".join(
            secrets.choice(string.ascii_letters + string.digits)
            for _ in range(16))).encode()
        client._t402 = response.t402
        client._siginfo.g = md5(DEVICE.guid + client._siginfo.dpwd +
                                client._t402).digest()

    if isinstance(response, LoginSuccess):
        client._t150 = response.t150 or client._t150
        client._rollback_sig = response.rollback_sig or client._rollback_sig
        client._time_diff = response.time_diff or client._time_diff
        client._ip_address = response.ip_address or client._ip_address
        client._t528 = response.t528 or client._t528
        client._t530 = response.t530 or client._t530
        client._ksid = response.ksid or client._ksid
        client._pwd_flag = response.pwd_flag or client._pwd_flag
        client._nick = response.nick or client._nick
        client._age = response.age or client._age
        client._gender = response.gender or client._gender

        client._siginfo.d2 = response.d2 or client._siginfo.d2
        client._siginfo.d2key = response.d2key or client._siginfo.d2key
        client._siginfo.tgt = response.tgt or client._siginfo.tgt
        client._siginfo.tgt_key = response.tgt_key or client._siginfo.tgt_key
        client._siginfo.device_token = (response.device_token
                                        or client._siginfo.device_token)
        client._siginfo.no_pic_sig = (response.no_pic_sig
                                      or client._siginfo.no_pic_sig)
        client._siginfo.encrypted_a1 = (response.encrypted_a1
                                        or client._siginfo.encrypted_a1)
        client._siginfo.ps_key_map = (response.ps_key_map
                                      or client._siginfo.ps_key_map)
        client._siginfo.pt4_token_map = (response.pt4_token_map
                                         or client._siginfo.pt4_token_map)
        client._siginfo.rand_seed = (response.rand_seed
                                     or client._siginfo.rand_seed)
        client._siginfo.s_key = response.s_key or client._siginfo.s_key
        client._siginfo.user_st_key = (response.user_st_key
                                       or client._siginfo.user_st_key)
        client._siginfo.user_st_web_sig = (response.user_st_web_sig
                                           or client._siginfo.user_st_web_sig)
        client._siginfo.wt_session_ticket = (response.wt_session_ticket or
                                             client._siginfo.wt_session_ticket)
        client._siginfo.wt_session_ticket_key = (
            response.wt_session_ticket_key
            or client._siginfo.wt_session_ticket_key)

        key = md5(client._password_md5 + bytes(4) +
                  struct.pack(">I", client._uin)).digest()
        decrypted = qqtea_decrypt(response.encrypted_a1, key)
        DEVICE.tgtgt = decrypted[51:67]
    elif isinstance(response, NeedCaptcha):
        client._t104 = response.t104 or client._t104
    elif isinstance(response, DeviceLocked):
        client._t104 = response.t104 or client._t104
        client._t174 = response.t174 or client._t174
        client._siginfo.rand_seed = (response.rand_seed
                                     or client._siginfo.rand_seed)
    elif isinstance(response, DeviceLockLogin):
        client._t104 = response.t104 or client._t104
        client._siginfo.rand_seed = (response.rand_seed
                                     or client._siginfo.rand_seed)
    return response