0

I'm trying to make a server for a password manager I'm building, but the server seems to hang randomly and it seems to randomly throw rsa.pkcs1.DecryptionErrors randomly too. I did recently switch from sending an END message to the server that then just made the server stop expecting stuff, to having a test script I wrote close the connection and then the server checks if socket.fileno() == -1. Maybe that's throwing a wrench in things. But it was doing this even before I switched. Right now, most of the time its throwing a fit trying to decode the password. Here is the server code:

import json

import rsa
import socket
import os.path
import netifaces
import json_repair

def get_connection_data():
    if os.path.exists("data/data.json"):
        connection_data = tuple(json_repair.from_file("data/data.json"))

    else:
        interface = netifaces.interfaces()[int(input(f"Enter the index of the interface you want to use. Eg, to use {netifaces.interfaces()[0]} enter 1\n{netifaces.interfaces()}\n")) - 1]
        port = input("What port do you want to user? Press enter for the default \n")

        if port == "":
            port = 9000

        connection_data = (
            netifaces.ifaddresses(interface)[netifaces.AF_INET][0]["addr"],
            port
        )

        if not os.path.exists("data"):
            os.mkdir("data")

        with open("data/data.json", mode="w") as connection_file:
            json.dump(connection_data, connection_file, indent=4)

    return connection_data

def register_user(user_client, device_address: float):
    print("register_user called")

    # Make sure data path exists
    if not os.path.exists("data"):
        os.mkdir("data")

    if not os.path.exists(f"data/{device_address}"):
        os.mkdir(f"data/{device_address}")

    all_passwords = {}

    # receive all passwords
    while True:
        service = rsa.decrypt(user_client.recv(1024), priv_key=private_key).decode()

        print("Service is:" + service)


        while service != "END":
            user_client.send("READY".encode())

            username = rsa.decrypt(user_client.recv(1024), priv_key=private_key).decode()

            print("Username is: " + username)

            user_client.send("READY".encode())

            print("Sent ready after receiving username")

            password = rsa.decrypt(user_client.recv(1024), priv_key=private_key).decode()
            print(password)
            user_client.send("READY".encode())

            print("Sent ready after receiving password")

            key = rsa.decrypt(user_client.recv(1024), priv_key=private_key)
            user_client.send("READY".encode())

            print("Sent ready after receiving key")

            if user_client.fileno() == -1:
                break

        if user_client.fileno() == -1:
            break

    all_passwords[service] = {
        username: {
            "password": password,
            "key": key.decode()
        }
    }

    with open(f"data/{device_address}/.passwords.json", mode="w") as passwords_file:
        json.dump(all_passwords, passwords_file, indent=4)

public_key, private_key = rsa.newkeys(1024)
client_public_key = None

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(get_connection_data())
server.listen()

print(f"Listening on {get_connection_data()[0]}:{get_connection_data()[1]}")

while True:
    client, ip_address = server.accept()

    print("Connection accepted")

    client.send(public_key.save_pkcs1("PEM"))
    client_public_key = rsa.PublicKey.load_pkcs1(client.recv(1024))

    print("Received and sent Public keys")

    action = client.recv(1024)# .decode("utf-8")
    # print("Received Action")

    # print(action)

    client.send("READY".encode())
    print("Sent ready message")


    if action.decode().lower() == "register user":
        print("Inside if statement")
        register_user(user_client=client, device_address=ip_address[0])

And here is the test script I put together:

import socket
import time

import rsa

IP_ADDRESS = input("Enter server IP: ")
PORT = 9000

pub_key, priv_key = rsa.newkeys(1024)
server_pub_key = None

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print("Connecting to server")

server.connect((IP_ADDRESS, PORT))

print("Receiving server public key and sending public key")

server_pub_key = rsa.PublicKey.load_pkcs1(server.recv(1024))
server.send(pub_key.save_pkcs1("PEM"))

message = "register user"

server.send(message.encode("utf-8"))
print("Sent action")

time.sleep(1)

print("Waiting for ready message")
server.recv(1024)
print("Received ready message")

all_passwords = {
        "service": {
            "username": {
                "password": "password",
                "key": "key"
                },
            "username2": {
                "password": "password2",
                "key": "key2",
                }
            },

            "service2": {
                "username": {
                    "password": "password",
                    "key": "key"
                },

                "username2": {
                    "password": "password2",
                    "key": "key2",
                }
            }
        }

for service in all_passwords:
    service_data = all_passwords[service]

    service = service

    print("Sending service")

    server.send(rsa.encrypt(service.encode(), pub_key=server_pub_key))
    server.recv(1024)

    for username in service_data.keys():
        username = username
        password = service_data[username]["password"]
        key = service_data[username]["key"]

        print(f"Service: {service} \nUsername: {username} \nPassword: {password} \nKey: {key}")

        server.send(rsa.encrypt(username.encode(), pub_key=server_pub_key))
        server.recv(1024)

        print("Received ready after sending username")

        server.send(rsa.encrypt(password.encode(), pub_key=server_pub_key))
        server.recv(1024)

        print("Received ready after sending password")

        server.send(rsa.encrypt(key.encode(), pub_key=server_pub_key))
        server.recv(1024)

        print("received ready after sending key")

server.close()

If anyone knows any better ways to do this, please let me know

I've checked the public and private keys probably 4 times by now, and I've tried going line by line through my code, but nothing caught my eye. I also did some brief searches on brave, found a thread where this was happening in cpython, clicked on it, and immediately went back cause it went straight over my head. Also, something I noticed is when I print the decoded password, using this code:

print(rsa.decrypt(user_client.recv(1024), priv_key=private_key).decode())
return

It runs without a problem, properly decrypting the password. Most of the time. Every once in a while, it also will give me a fit about decrypting the password

EDIT: I also tried sending an END message from the test script and then having the server close the connection, but that didn't change anything

8
  • socket.fileno() is never going to magically become -1 unless this application closes the socket, and maybe not even then. You should test for end of stream on a read if you don't have a specific END message. So you are undoubtedly processing garbage after the peer closes. Commented Jun 26 at 1:39
  • Ohhhh. OK. So if I send an END message, then the function that the server runs should just return? Or should it close the connection? Commented Jun 26 at 18:30
  • If you get EOS from a read you must close the connection. If you have an END message and receive it you should also close the connection, but you have to close on EOS anyway, e.g. in case they didn't send END, so the END message is pretty pointless, unless you need to defend against truncation attacks, in which case you should be using TLS. Commented Jun 27 at 1:17
  • What is EOS? How do I close on EOS? Commented Jun 27 at 17:03
  • 1
    Get in the habit of reading the documentation for the functions you are using. "EOS" just means end of stream, just like "EOF" means end of file. The documentation for [socket.recv()](https://docs.python.org/3/library/socket.html#socket.socket.recv) says "...A returned empty bytes object indicates that the client has disconnected...". So check the returned bytes object from the recv` call if it is empty (i.e., has length 0), then the peer has finished sending and has closed the connection, so you can do the same. Commented Jun 28 at 0:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.