Пример #1
0
class LANClient:
    def __init__(self, settings, key):
        if isinstance(settings, Settings):
            self.settings = settings.copy()
        else:
            self.settings = Settings(settings)

        self.key = key

        self.nonce_counter = 0

        self.broadcast = (util.broadcast_address(), 30000)

    def configure(self, version):
        self.settings.set("pia.version", version)
        self.settings.set("pia.lan_version", self.lan_version(version))
        self.settings.set("pia.station_extension", version < 50000)
        self.settings.set("pia.crypto_enabled", version >= 50900)

    def lan_version(self, version):
        if version >= 51100: return 2
        if version >= 50900: return 1
        return 0

    def generate_challenge_key(self, key):
        aes = AES.new(self.key, AES.MODE_ECB)
        return aes.encrypt(key)

    def generate_nonce(self, counter):
        broadcast = socket.inet_aton(self.broadcast[0])
        return broadcast + struct.pack(">Q", counter)

    def generate_challenge_reply(self, nonce, key, challenge):
        key = hmac.new(self.key, key, digestmod=hashlib.sha256).digest()[:16]
        data = hmac.new(self.key, challenge,
                        digestmod=hashlib.sha256).digest()[:16]

        aes = AES.new(key, AES.MODE_GCM, nonce=nonce)
        ciphertext, tag = aes.encrypt_and_digest(data)
        return tag + ciphertext
Пример #2
0
		
		response = common.RMCResponse()
		response.result = common.Result(0x10001) #Success
		response.connection_id = next(self.connection_id)
		response.public_station = station
		return response
	
	def register_ex(self, context, urls, login_data):
		return self.register(context, urls)


class FriendsServer(friends.FriendsServer):
	pass #Implement friend server methods here


settings = Settings("friends.cfg")
settings.set("server.access_key", Friends.ACCESS_KEY)

auth_server = service.RMCServer(settings)
auth_server.register_protocol(AuthenticationServer(settings))
auth_server.start("", 1223)

server_key = derive_key(get_user_by_name("Quazal Rendez-Vous"))

secure_server = service.RMCServer(settings)
secure_server.register_protocol(SecureConnectionServer())
secure_server.register_protocol(FriendsServer())
secure_server.start("", 1224, key=server_key)

input("Press enter to exit...\n")
Пример #3
0
class PIASession:
    def __init__(self, settings=None):
        if isinstance(settings, Settings):
            self.settings = settings.copy()
        else:
            self.settings = Settings(settings)

        self.stations = StationTable()
        self.transport = MessageTransport(self)
        self.resender = ResendingTransport(self.transport)
        self.mesh = Mesh()

        self.session_key = None
        self.my_station = None

        self.session_settings = None

        self.protocols = {}

    def configure(self, version):
        self.settings.set("pia.version", version)
        self.settings.set("pia.station_extension", version < 50000)
        self.settings.set("pia.crypto_enabled", version >= 50900)
        if version >= 50900:
            self.settings.set("pia.encryption_method", 1)
            self.settings.set("pia.signature_method", 0)
        if version >= 51100:
            self.settings.set("pia.header_version", 4)
        if version >= 50900:
            self.settings.set("pia.protocol_type_revision", 1)
        self.settings.set("pia.message_version",
                          self.derive_message_version(version))

    def derive_message_version(self, pia_version):
        major_version = pia_version // 100
        if major_version <= 503: return 0
        if major_version in [509, 510]: return 1
        if major_version == 511: return 2
        if 514 <= major_version <= 517: return 3
        if major_version == 518: return 4
        raise ValueError("Unsupported PIA version: %i" % pia_version)

    def register_protocol(self, protocol):
        self.protocols[protocol.get_protocol_type()] = protocol

    def create_protocols(self):
        self.station_protocol = StationProtocol(self)
        self.mesh_protocol = MeshProtocol(self)
        self.unreliable_protocol = UnreliableProtocol(self)

        self.register_protocol(self.station_protocol)
        self.register_protocol(self.mesh_protocol)
        self.register_protocol(self.unreliable_protocol)

    def get_protocol(self, type):
        return self.protocols[type]

    def prepare(self, identification_info):
        logger.info("Initializing PIA session")
        self.create_protocols()

        self.transport.prepare()

        location = self.prepare_station_location()

        connection_info = StationConnectionInfo(location)

        self.my_station = self.stations.create()
        self.my_station.connection_state = ConnectionState.CONNECTED
        self.my_station.address = self.transport.local_address()
        self.my_station.connection_info = connection_info
        self.my_station.identification_info = identification_info
        self.my_station.id = self.build_station_id()

        self.event = scheduler.add_socket(self.handle_recv, self.transport)

    def cleanup(self):
        scheduler.remove(self.event)
        self.transport.cleanup()

    def create_mesh(self, session_key, settings):
        self.session_key = session_key
        self.session_settings = settings

        self.mesh.create(self.my_station)

    def join_mesh(self, session_key, host_location):
        self.session_key = session_key

        connection_info = StationConnectionInfo(host_location)

        address = host_location.local.address
        host = self.stations.create()
        host.address = address.host, address.port
        host.connection_info = connection_info
        self.connect_station(host)
        host.wait_connected()

        self.mesh_protocol.join(host)

    def leave_mesh(self):
        pass

    def connect_station(self, station):
        self.station_protocol.connect(station)

    def handle_recv(self, pair):
        station, message = pair

        protocol_id = message.protocol_id
        if protocol_id in self.protocols:
            self.protocols[protocol_id].handle(station, message)
        else:
            logger.warning("Unknown protocol id: 0x%X" % protocol_id)

    def get_mesh(self):
        return self.mesh

    def get_station_table(self):
        return self.stations

    def local_station(self):
        return self.my_station

    def host_station(self):
        index = self.mesh.get_host_index()
        return self.stations.find_by_index(index)

    def is_host(self):
        return self.local_station() == self.host_station()

    def get_game_mode(self):
        return self.session_settings.game_mode

    def get_attributes(self):
        return self.session_settings.attributes

    def get_num_participants(self):
        return self.mesh.get_num_participants()

    def get_min_participants(self):
        return self.session_settings.min_participants

    def get_max_participants(self):
        return self.session_settings.max_participants

    def get_session_type(self):
        return self.session_settings.session_type

    def get_application_data(self):
        return self.session_settings.application_data

    def get_session_key(self):
        return self.session_key

    def set_session_key(self, key):
        self.session_key = key

    def join(self, session):
        raise NotImplementedError

    def create(self):
        raise NotImplementedError

    def leave(self):
        raise NotImplementedError

    def generate_nonce(self, packet):
        raise NotImplementedError

    def get_session_id(self):
        raise NotImplementedError

    def build_station_id(self):
        raise NotImplementedError
Пример #4
0
class BackEndClient:
    def __init__(self, settings=None):
        if isinstance(settings, Settings):
            self.settings = settings.copy()
        else:
            self.settings = Settings(settings)

        self.auth_client = service.RMCClient(self.settings)
        self.secure_client = service.RMCClient(self.settings)

        self.auth_proto = authentication.AuthenticationClient(self.auth_client)
        self.secure_proto = secure.SecureConnectionClient(self.secure_client)

        if self.settings.get("kerberos.key_derivation") == 0:
            self.key_derivation = kerberos.KeyDerivationOld(65000, 1024)
        else:
            self.key_derivation = kerberos.KeyDerivationNew(1, 1)

        self.pid = None
        self.local_station = None
        self.public_station = None

    def configure(self, access_key, nex_version, client_version=None):
        self.settings.set("nex.access_key", access_key)
        self.settings.set("nex.version", nex_version)
        if nex_version >= 40500:
            if client_version is None:
                raise ValueError(
                    "Must specify client version for NEX 4.5.0 or later")
            self.settings.set("nex.client_version", client_version)
        self.auth_client.set_access_key(access_key)
        self.secure_client.set_access_key(access_key)

    def connect(self, host, port):
        # Connect to authentication server
        if not self.auth_client.connect(host, port, 1):
            raise ConnectionError("Couldn't connect to authentication server")

    def close(self):
        self.auth_client.close()
        self.secure_client.close()

    def login(self, username, password=None, auth_info=None, login_data=None):
        if self.settings.get("nex.version") < 40500:
            result = self.login_normal(username, auth_info)
        else:
            result = self.login_with_param(username, auth_info)

        self.pid = result.pid

        secure_station = result.secure_station

        kerberos_key = result.ticket_key
        if not kerberos_key:
            if not password:
                raise ValueError("A password is required for this account")

            # Derive kerberos key from password
            kerberos_key = self.key_derivation.derive_key(
                password.encode(), self.pid)

        # Decrypt ticket from login response
        ticket = kerberos.ClientTicket()
        ticket.decrypt(result.ticket, kerberos_key, self.settings)

        if ticket.target_pid != secure_station["PID"]:
            # Request ticket for secure server
            response = self.auth_proto.request_ticket(self.pid,
                                                      secure_station["PID"])

            # Check for errors and decrypt ticket
            response.result.raise_if_error()
            ticket = kerberos.ClientTicket()
            ticket.decrypt(response.ticket, kerberos_key, self.settings)

        ticket.source_pid = self.pid
        ticket.target_cid = secure_station["CID"]

        # The secure server may reside at the same
        # address as the authentication server
        host = secure_station["address"]
        port = secure_station["port"]
        if host == "0.0.0.1":
            host, port = self.auth_client.remote_address()

        # Connect to secure server
        server_sid = secure_station["sid"]
        if not self.secure_client.connect(host, port, server_sid, ticket):
            raise ConnectionError("Couldn't connect to secure server")

        # Create a stationurl for our local client address
        client_addr = self.secure_client.local_address()
        self.local_station = common.StationURL(
            address=client_addr[0],
            port=client_addr[1],
            sid=self.secure_client.stream_id(),
            natm=0,
            natf=0,
            upnp=0,
            pmp=0)

        # Register urls on secure server
        if login_data:
            response = self.secure_proto.register_ex([self.local_station],
                                                     login_data)
        else:
            response = self.secure_proto.register([self.local_station])

        # Check for errors and update urls
        response.result.raise_if_error()
        self.public_station = response.public_station
        self.public_station["RVCID"] = response.connection_id
        self.local_station["RVCID"] = response.connection_id

    def login_normal(self, username, auth_info):
        if auth_info:
            response = self.auth_proto.login_ex(username, auth_info)
        else:
            response = self.auth_proto.login(username)
        response.result.raise_if_error()
        return LoginResult(response.pid, response.ticket, None,
                           response.connection_data.main_station)

    def login_with_param(self, username, auth_info):
        param = authentication.ValidateAndRequestTicketParam()
        param.username = username
        if auth_info:
            param.data = auth_info
        else:
            param.data = common.NullData()
        param.nex_version = self.settings.get("nex.version")
        param.client_version = self.settings.get("nex.client_version")

        response = self.auth_proto.login_with_param(param)

        return LoginResult(response.pid, response.ticket,
                           bytes.fromhex(response.ticket_key),
                           response.server_url)

    def login_guest(self):
        self.login("guest", "MMQea3n!fsik")

    def get_pid(self):
        return self.pid
Пример #5
0
        response = common.RMCResponse()
        response.result = common.Result(0x10001)  #Success
        response.connection_id = next(self.connection_id)
        response.public_station = station
        return response

    def register_ex(self, context, urls, login_data):
        return self.register(context, urls)


class FriendsServer(friends.FriendsServer):
    pass  #Implement friend server methods here


settings = Settings("friends.cfg")
settings.set("nex.access_key", Friends.ACCESS_KEY)

auth_server = service.RMCServer(settings)
auth_server.register_protocol(AuthenticationServer(settings))
auth_server.start("", 1223)

server_key = derive_key(get_user_by_name("Quazal Rendez-Vous"))

secure_server = service.RMCServer(settings)
secure_server.register_protocol(SecureConnectionServer())
secure_server.register_protocol(FriendsServer())
secure_server.start("", 1224, key=server_key)

input("Press enter to exit...\n")
Пример #6
0
class BackEndClient:
    def __init__(self, access_key, version, settings=None):
        if settings:
            self.settings = settings.copy()
        else:
            self.settings = Settings()
        self.settings.set("server.access_key", access_key)
        self.settings.set("server.version", version)

        self.auth_client = service.RMCClient(self.settings)
        self.secure_client = service.RMCClient(self.settings)

        self.auth_proto = authentication.AuthenticationClient(self.auth_client)
        self.secure_proto = secure.SecureConnectionClient(self.secure_client)

        if self.settings.get("kerberos.key_derivation") == 0:
            self.key_derivation = kerberos.KeyDerivationOld(65000, 1024)
        else:
            self.key_derivation = kerberos.KeyDerivationNew(1, 1)

        self.my_pid = None
        self.local_station = None
        self.public_station = None

    def connect(self, host, port):
        # Connect to authentication server
        if not self.auth_client.connect(host, port, 1):
            raise ConnectionError("Couldn't connect to authentication server")

    def close(self):
        self.auth_client.close()
        self.secure_client.close()

    def login(self, username, password, auth_info=None, login_data=None):
        # Call login method on authentication protocol
        if auth_info:
            response = self.auth_proto.login_ex(username, auth_info)
        else:
            response = self.auth_proto.login(username)

        # Check for errors
        response.result.raise_if_error()

        self.my_pid = response.pid

        secure_station = response.connection_data.main_station

        # Derive kerberos key from password
        kerberos_key = self.key_derivation.derive_key(password.encode("ascii"),
                                                      response.pid)

        # Decrypt ticket from login response
        ticket = kerberos.ClientTicket()
        ticket.decrypt(response.ticket, kerberos_key, self.settings)

        if ticket.target_pid != secure_station["PID"]:
            # Request ticket for secure server
            response = self.auth_proto.request_ticket(self.my_pid,
                                                      secure_station["PID"])

            # Check for errors and decrypt ticket
            response.result.raise_if_error()
            ticket = kerberos.ClientTicket()
            ticket.decrypt(response.ticket, kerberos_key, self.settings)

        ticket.source_pid = self.my_pid
        ticket.target_cid = secure_station["CID"]

        # The secure server may reside at the same
        # address as the authentication server
        host = secure_station["address"]
        port = secure_station["port"]
        if host == "0.0.0.1":
            host, port = self.auth_client.remote_address()

        # Connect to secure server
        server_sid = secure_station["sid"]
        if not self.secure_client.connect(host, port, server_sid, ticket):
            raise ConnectionError("Couldn't connect to secure server")

        # Create a stationurl for our local client address
        client_addr = self.secure_client.local_address()
        self.local_station = common.StationURL(
            address=client_addr[0],
            port=client_addr[1],
            sid=self.secure_client.stream_id(),
            natm=0,
            natf=0,
            upnp=0,
            pmp=0)

        # Register urls on secure server
        if login_data:
            response = self.secure_proto.register_ex([self.local_station],
                                                     login_data)
        else:
            response = self.secure_proto.register([self.local_station])

        # Check for errors and update urls
        response.result.raise_if_error()
        self.public_station = response.public_station
        self.public_station["RVCID"] = response.connection_id
        self.local_station["RVCID"] = response.connection_id

    def login_guest(self):
        self.login("guest", "MMQea3n!fsik")

    def get_pid(self):
        return self.my_pid