示例#1
0
 def makeFirstConnectCell(self):
     """add method def"""
     ECprivate_key = ec.generate_private_key(
         ec.SECP384R1(), default_backend())  # elliptic curve
     DHpublicKeyBytes = ECprivate_key.public_key().public_bytes(
         encoding=serialization.Encoding.PEM,
         format=serialization.PublicFormat.SubjectPublicKeyInfo)
     # send the initialising cell, by sending the DHpublicKeyBytes
     sendingCell = cell(DHpublicKeyBytes, Type="AddCon")
     return sendingCell, ECprivate_key
示例#2
0
    def exchange_keys(self, clientsocket, obtainedCell):
        """Exchange Key with someone, obtaining a shared secret. Also, generate salt
        and pass it back to them with your private key."""

        private_key = ec.generate_private_key(
            ec.SECP384R1(), default_backend())  # elliptic curve
        public_key = private_key.public_key()  # duh same.
        serialised_public_key = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo)
        # serialise the public key that I'm going to send them

        theirkey = serialization.load_pem_public_key(obtainedCell.payload,
                                                     backend=default_backend())
        shared_key = private_key.exchange(ec.ECDH(), theirkey)
        salty = str.encode(str(randint(0, 99999999)))  # randomised IV
        derived_key = HKDF(algorithm=hashes.SHA256(),
                           length=32,
                           salt=salty,
                           info=None,
                           backend=default_backend()).derive(shared_key)
        reply_cell = cell(serialised_public_key,
                          salt=salty,
                          Type="ConnectResp")
        signature = self.true_private_key.sign(
            salty,
            cryptography.hazmat.primitives.asymmetric.padding.PSS(
                mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(
                    hashes.SHA256()),
                salt_length=cryptography.hazmat.primitives.asymmetric.padding.
                PSS.MAX_LENGTH), hashes.SHA256())
        reply_cell.signature = signature  # assign the signature.
        print("reply cell")
        print(pickle.dumps(reply_cell))
        # send them the serialised version.
        clientsocket.send(pickle.dumps(reply_cell))
        return private_key, derived_key
示例#3
0
    def main(self):
        """main method"""
        client_class = None  # initialise as none.
        readready, _, _ = select.select([self.server_socket] +
                                        self.CLIENTSOCKS, [], [])
        for i in readready:
            if (i == self.server_socket):  # i've gotten a new connection
                print("client get")
                (clientsocket, _) = self.server_socket.accept()
                # clientsocket.setblocking(0)
                clientsocket.settimeout(0.3)
                try:
                    obtainedCell = clientsocket.recv(
                        4096)  # obtain their public key
                    try:
                        print("raw data obtained. (Cell)")
                        print(obtainedCell)
                        # decrypt the item.
                        obtainedCell = self.decrypt(obtainedCell)

                    # this is due to decryption failure.
                    except ValueError:
                        if client_class is not None:
                            self.CLIENTS.remove(client_class)
                            # just in case.
                            # otherwise, it should continue
                        print("rejected one connection")
                        continue
                    print("decrypted cell with actual keys.")
                    print(obtainedCell)
                    # i.e grab the cell that was passed forward.
                    obtainedCell = pickle.loads(obtainedCell)
                    print("after pickle load")
                    print(obtainedCell)
                    if obtainedCell.type != "AddCon":
                        break  # it was not a connection request.
                    # obtain the generated public key, and the derived key.
                    generatedPrivateKey, derivedkey = self.exchange_keys(
                        clientsocket, obtainedCell)
                    client_class = Client(clientsocket, derivedkey,
                                          generatedPrivateKey)
                    self.CLIENTS.append(client_class)
                    self.CLIENTSOCKS.append(clientsocket)
                    print(client_class.socket.getpeername())
                    print("Connected to ONE client.\n\n\n")

                # error is socket error here.
                except (error, ConnectionResetError, timeout):
                    print("socket ERROR! might have timed out.")
                    if client_class is not None:
                        self.CLIENTS.remove(client_class)
                        # just in case.
                        # otherwise, it should continue
                    continue

            else:  # came from an existing client.
                try:
                    for k in self.CLIENTS:
                        if k.socket == i:
                            sending_client = k
                    received = i.recv(4096)
                    print("got a packet..")
                    print(received)
                    if not received:
                        raise ConnectionResetError
                except (error, ConnectionResetError, ConnectionAbortedError,
                        timeout):
                    print("Client was closed or timed out.")
                    sending_client.socket.close()
                    if sending_client.bounce_socket is not None:
                        sending_client.bounce_socket.close()
                    self.CLIENTSOCKS.remove(i)
                    self.CLIENTS.remove(sending_client)
                    continue
                print("existing")
                # received_data = self.decrypt(received)
                gottencell = pickle.loads(received)
                derived_key = sending_client.key  # take his derived key
                cipher = Cipher(algorithms.AES(derived_key),
                                modes.CBC(gottencell.IV),
                                backend=default_backend())
                decryptor = cipher.decryptor()
                decrypted = decryptor.update(gottencell.payload)
                decrypted += decryptor.finalize()
                cell_to_next = pickle.loads(decrypted)
                print(cell_to_next.type)
                if cell_to_next.type == "relay connect":  # is a request for a relay connect
                    try:
                        # your connection is TCP.
                        sock = socket(AF_INET, SOCK_STREAM)
                        sock.connect((cell_to_next.ip, cell_to_next.port))
                        print((cell_to_next.ip, cell_to_next.port))
                        print("cell to next")
                        print(decrypted)
                        print("payload")
                        print(cell_to_next.payload)
                        # send over the cell payload
                        sock.send(cell_to_next.payload)
                        theircell = sock.recv(4096)  # await answer
                        print("got values")
                        print(theircell)
                        IV = os.urandom(16)
                        cipher = Cipher(algorithms.AES(derived_key),
                                        modes.CBC(IV),
                                        backend=default_backend())
                        encryptor = cipher.encryptor()
                        if (theircell == b""):
                            encrypted = encryptor.update(
                                padder128(pickle.dumps(cell("",
                                                            Type="failed"))))
                            encrypted += encryptor.finalize()
                            print("sent failed")
                            i.send(
                                pickle.dumps(
                                    cell(encrypted, IV=IV, Type="failed")))
                        else:
                            encrypted = encryptor.update(
                                padder128(
                                    pickle.dumps(
                                        cell(theircell, Type="ConnectResp"))))
                            encrypted += encryptor.finalize()
                            print("sent valid response")
                            i.send(
                                pickle.dumps(
                                    cell(encrypted, IV=IV, Type="AddCon")))
                            sending_client.bounce_ip = cell_to_next.ip
                            sending_client.bounce_port = cell_to_next.port
                            sending_client.bounce_socket = sock
                            print("connection success.\n\n\n\n\n")
                    except (ConnectionRefusedError, ConnectionResetError,
                            ConnectionAbortedError, error, timeout) as e:
                        print(
                            "failed to connect to other server. sending back failure message, or timed out."
                        )
                        IV = os.urandom(16)
                        cipher = Cipher(algorithms.AES(derived_key),
                                        modes.CBC(IV),
                                        backend=default_backend())
                        encryptor = cipher.encryptor()
                        encrypted = encryptor.update(
                            padder128(
                                pickle.dumps(
                                    cell(pickle.dumps(
                                        cell("CONNECTIONREFUSED",
                                             Type="failed")),
                                         Type="failed"))))
                        encrypted += encryptor.finalize()
                        i.send(
                            pickle.dumps(cell(encrypted, IV=IV,
                                              Type="failed")))
                        print("sent back failure message.")

                # is an item to be relayed.
                elif cell_to_next.type == "relay":
                    if sending_client.bounce_socket is None:  # check if there is bounce socket
                        return
                    sock = sending_client.bounce_socket
                    print("bouncing cell's decrypted..")
                    print(decrypted)
                    print("payload")
                    print(cell_to_next.payload)
                    print(cell_to_next.type)
                    sock.send(cell_to_next.payload)  # send over the cell
                    try:
                        theircell = sock.recv(32768)  # await answer
                    except timeout:
                        theircell = "request timed out!"
                    print("got answer back.. as a relay.")
                    print(len(theircell))
                    print(theircell)
                    IV = os.urandom(16)
                    cipher = Cipher(algorithms.AES(derived_key),
                                    modes.CBC(IV),
                                    backend=default_backend())
                    encryptor = cipher.encryptor()
                    encrypted = encryptor.update(
                        padder128(
                            pickle.dumps(cell(theircell, Type="ConnectResp"))))
                    encrypted += encryptor.finalize()
                    i.send(pickle.dumps(cell(encrypted, IV=IV, Type="AddCon")))
                    print("Relay success.\n\n\n\n\n")
                elif cell_to_next.type == "Req":
                    print(cell_to_next.payload)
                    if isinstance(cell_to_next.payload, type("")):
                        request = cell_to_next.payload
                        try:
                            header = {
                                "User-Agent":
                                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"
                            }
                            a = requests.get(request, headers=header)
                            print("length of answer")
                            print(len(a.content))
                        except requests.exceptions.ConnectionError:
                            a = "ERROR"
                            print(
                                "failed to receive a response from the website."
                            )

                        IV = os.urandom(16)
                        cipher = Cipher(algorithms.AES(derived_key),
                                        modes.CBC(IV),
                                        backend=default_backend())
                        encryptor = cipher.encryptor()
                        encrypted = encryptor.update(
                            padder128(
                                pickle.dumps(
                                    cell(pickle.dumps(a),
                                         Type="ConnectResp"))))
                        encrypted += encryptor.finalize()
                        i.send(
                            pickle.dumps(cell(encrypted, IV=IV,
                                              Type="AddCon")))
                        print("VALID REQUEST REPLIED.")
                    else:
                        IV = os.urandom(16)
                        cipher = Cipher(algorithms.AES(derived_key),
                                        modes.CBC(IV),
                                        backend=default_backend())
                        encryptor = cipher.encryptor()
                        encrypted = encryptor.update(
                            padder128(
                                pickle.dumps(
                                    cell("INVALID REQUEST DUMDUM",
                                         Type="ConnectResp"))))
                        encrypted += encryptor.finalize()
                        i.send(
                            pickle.dumps(cell(encrypted, IV=IV,
                                              Type="AddCon")))
                        print("INVALID REQUEST SENT BACK")
示例#4
0
    def mainloop(self):
        while (True):
            """if ((time.time() - self.lasttime) > 20.00):
                for i in self.registered_servers:
                    i.time = time.time()
                    i.socket.send(cell("",Type= "checkup"))
                    
            else:
            """
            #SOME INDENTATION.
            readready, _, _ = select.select([self.socket] + self.socketlist,
                                            [], [])
            print("obtained a server connection.")
            for i in readready:
                if (i == self.socket):  #is receiving a new connection request.
                    (serversocket, myport) = readready[0].accept
                    obtained = serversocket.recv(
                        4096)  # obtain the data sent over.
                    try:
                        receivedCell = pickle.loads(obtained)
                    except (pickle.PickleError, pickle.PicklingError,
                            pickle.UnpicklingError) as e:
                        continue

                    if (type(receivedCell) == type(
                            cell(""))):  #ensure it is indeed a cell.
                        if (receivedCell.type == "giveDirect"):  #
                            signedbytearray = receivedCell.salt
                            signature = receivedCell.signature
                            identity = receivedCell.payload

                            try:
                                tempopen = open(
                                    "publics/publictest" + str(identity) +
                                    ".pem", "rb")
                                theirpublickey = serialization.load_pem_private_key(
                                    tempopen.read(),
                                    password=None,
                                    backend=default_backend(
                                    ))  # used for signing, etc.
                                tempopen.close()
                            except FileNotFoundError:
                                continue  #i.e the identity is not established.

                            try:
                                theirpublickey.verify(
                                    signature, signedbytearray,
                                    cryptography.hazmat.primitives.asymmetric.
                                    padding.PSS(
                                        mgf=cryptography.hazmat.primitives.
                                        asymmetric.padding.MGF1(
                                            hashes.SHA256()),
                                        salt_length=cryptography.hazmat.
                                        primitives.asymmetric.padding.PSS.
                                        MAX_LENGTH), hashes.SHA256())
                            except InvalidSignature:
                                serversocket.close(
                                )  #reject. signature validation failed.
                                continue
                            ip, port = serversocket.getpeername(
                            )  # obtain the ip and port of that server.
                            ##
                            """
                            firstlatency = time.time()
                            serversocket.send(cell("",Type="checkup"))
                            serversocket.recv(4096)
                            secondlatency = time.time()
                            latency = secondlatency-firstlatency
                            """
                            self.registered_servers.append(
                                Serverreg(ip, port, serversocket, identity,
                                          latency))
                        else:
                            serversocket.close()
                            continue  # reject connection as it does not contain a valid cell.
                else:
                    print("got from existing.")
                    received = i.recv(4096)
                    for k in self.registered_servers:
                        if (k.socket == i):
                            # i.e it is part of the thing.
                            reference = k
                    if (len(received) == 0):  #disconnect catch
                        print("CLIENT WAS CLOSED! or timed out.")
                        i.socket.close()
                        self.registered_servers.remove(reference)
                        continue
                    """else: #am currently receiving an update
示例#5
0
    def req(self, request, intermediate_servers):
        """send out stuff in router."""
        #print("REQUEST SENDING TEST")
        # must send IV and a cell that is encrypted with the next public key
        # public key list will have to be accessed in order with list of servers.
        # number between is to know when to stop i guess.
        # connection type. exit node always knows
        sendingCell = cell(request, Type="Req")
        IV = os.urandom(16)
        cipher = Cipher(algorithms.AES(intermediate_servers[2].key),
                        modes.CBC(IV),
                        backend=default_backend())  # 256 bit length cipher lel
        encryptor = cipher.encryptor()  # encrypt the entire cell
        encrypted = encryptor.update(padder128(pickle.dumps(sendingCell)))
        encrypted += encryptor.finalize()  # finalise encryption.
        sendingCell = cell(encrypted, IV=IV, Type="relay")
        sendingCell.ip = intermediate_servers[2].ip
        sendingCell.port = intermediate_servers[2].port
        sendingCell = cell(pickle.dumps(sendingCell), Type="relay")

        IV = os.urandom(16)
        cipher = Cipher(algorithms.AES(intermediate_servers[1].key),
                        modes.CBC(IV),
                        backend=default_backend())  # 256 bit length cipher lel
        encryptor = cipher.encryptor()  # encrypt the entire cell
        encrypted = encryptor.update(padder128(pickle.dumps(sendingCell)))
        encrypted += encryptor.finalize()  # finalise encryption.
        sendingCell = cell(encrypted, IV=IV, Type="relay")
        sendingCell.ip = intermediate_servers[1].ip
        sendingCell.port = intermediate_servers[1].port
        sendingCell = cell(pickle.dumps(sendingCell), Type="relay")
        IV = os.urandom(16)

        cipher = Cipher(algorithms.AES(intermediate_servers[0].key),
                        modes.CBC(IV),
                        backend=default_backend())  # 256 bit length cipher lel
        encryptor = cipher.encryptor()  # encrypt the entire cell
        encrypted = encryptor.update(padder128(pickle.dumps(sendingCell)))
        encrypted += encryptor.finalize()  # finalise encryption.
        sendingCell = cell(encrypted, IV=IV, Type="relay")
        sendingCell.ip = intermediate_servers[0].ip
        sendingCell.port = intermediate_servers[0].port
        try:
            sock = intermediate_servers[0].socket
            sock.send(pickle.dumps(sendingCell))  # send over the cell
            their_cell = sock.recv(32768)  # await answer
            # you now receive a cell with encrypted payload.
            #print("received cell")
            # print(len(their_cell))
            # print(their_cell)
            their_cell = pickle.loads(their_cell)
            #print("received cell payload")
            # print(their_cell.payload)
            counter = 0
            while counter < len(intermediate_servers):
                cipher = Cipher(algorithms.AES(
                    intermediate_servers[counter].key),
                                modes.CBC(their_cell.IV),
                                backend=default_backend())
                decryptor = cipher.decryptor()
                decrypted = decryptor.update(their_cell.payload)
                decrypted += decryptor.finalize()  # finalise decryption
                their_cell = pickle.loads(decrypted)
                counter += 1
                if (counter < len(intermediate_servers)):
                    their_cell = pickle.loads(their_cell.payload)

            if (their_cell.type == their_cell._Types[3]):
                #print("FAILED AT CONNECTION!")
                return

            response = pickle.loads(their_cell.payload)
            if not isinstance(response, type("")):
                print(response.content)
                print(response.status_code)
                return_dict = {
                    "content": response.content.decode(response.encoding),
                    "status code": response.status_code
                }
                print(json.dumps(return_dict))
            else:
                # TODO - the error code should be specific to our implementation, not generic ones
                # e.g. node offline, decryption failure etc etc
                print(json.dumps({"content": "", "status": 404}))
        except error:
            print("socketerror")
示例#6
0
    def moreConnect2(self, gonnect, gonnectport, intermediate_servers,
                     RSA_key):
        """must send IV and a cell that is encrypted with the next public key
        public key list will have to be accessed in order with list of servers.
        number between is to know when to stop i guess."""

        sendingCell, ECprivate_key = self.makeFirstConnectCell()
        sendingCell = pickle.dumps(sendingCell)
        #print("Innermost cell with keys")
        # print(sendingCell)
        sendingCell = RSA_key.encrypt(
            sendingCell,
            cryptography.hazmat.primitives.asymmetric.padding.OAEP(
                mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(
                    algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None))
        #print("Innermost cell with keys (Encrypted)")
        # print(sendingCell)
        # connection type. exit node always knows
        sendingCell = cell(sendingCell, Type="relay connect")
        sendingCell.ip = gonnect
        # save the stuff i should be sending over.
        sendingCell.port = gonnectport
        IV = os.urandom(16)
        cipher = Cipher(algorithms.AES(intermediate_servers[1].key),
                        modes.CBC(IV),
                        backend=default_backend())  # 256 bit length cipher lel
        encryptor = cipher.encryptor()  # encrypt the entire cell
        encrypted = encryptor.update(padder128(pickle.dumps(sendingCell)))
        encrypted += encryptor.finalize()  # finalise encryption.
        sendingCell = cell(encrypted, IV=IV, Type="relay connect")
        sendingCell.ip = intermediate_servers[1].ip
        sendingCell.port = intermediate_servers[1].port
        sendingCell = cell(pickle.dumps(sendingCell), Type="relay")
        IV = os.urandom(16)

        cipher = Cipher(algorithms.AES(intermediate_servers[0].key),
                        modes.CBC(IV),
                        backend=default_backend())  # 256 bit length cipher lel
        encryptor = cipher.encryptor()  # encrypt the entire cell
        encrypted = encryptor.update(padder128(pickle.dumps(sendingCell)))
        encrypted += encryptor.finalize()  # finalise encryption.
        sendingCell = cell(encrypted, IV=IV, Type="relay")
        sendingCell.ip = intermediate_servers[0].ip
        sendingCell.port = intermediate_servers[0].port
        try:
            sock = intermediate_servers[0].socket
            sock.send(pickle.dumps(sendingCell))  # send over the cell
            their_cell = sock.recv(4096)  # await answer
            # you now receive a cell with encrypted payload.
            # print(their_cell)
            their_cell = pickle.loads(their_cell)
            # print(their_cell.payload)
            counter = 0
            while (counter < len(intermediate_servers)):
                cipher = Cipher(algorithms.AES(
                    intermediate_servers[counter].key),
                                modes.CBC(their_cell.IV),
                                backend=default_backend())
                decryptor = cipher.decryptor()
                decrypted = decryptor.update(their_cell.payload)
                decrypted += decryptor.finalize()  # finalise decryption
                # print(decrypted)
                their_cell = pickle.loads(decrypted)
                counter += 1
                their_cell = pickle.loads(their_cell.payload)
            if (their_cell.type == their_cell._Types[3]):
                #print("FAILED AT CONNECTION!")
                return
            # their_cell = pickle.loads(their_cell.payload)

            # this cell isn't encrypted. Extract the signature to verify
            signature = their_cell.signature
            their_cell.signature = None
            RSA_key.verify(
                signature, their_cell.salt,
                cryptography.hazmat.primitives.asymmetric.padding.PSS(
                    mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(
                        hashes.SHA256()),
                    salt_length=cryptography.hazmat.primitives.asymmetric.
                    padding.PSS.MAX_LENGTH), hashes.SHA256())
            # verify that the cell was signed using their key.
            # at this point, you have the cell that is the public key of your target server. Additionally, salt too..
            theirKey = serialization.load_pem_public_key(
                their_cell.payload,
                backend=default_backend())  # load up their key.
            shared_key = ECprivate_key.exchange(ec.ECDH(), theirKey)
            derived_key = HKDF(algorithm=hashes.SHA256(),
                               length=32,
                               salt=their_cell.salt,
                               info=None,
                               backend=default_backend()).derive(shared_key)
            self.serverList.append(
                Server(gonnect, sock, derived_key, ECprivate_key, RSA_key,
                       gonnectport))
            #print("connected successfully to server @ " + gonnect + "   Port: " + str(gonnectport))
        except error:
            print("socket error occurred")