0

I have a simple client-server program that uses python Paramiko.

The client sends an encrypted string to the server and the server needs to decrypt it to process it.

This is the client:

def collect_stats():
    try:
        cpu = psutil.cpu_percent(interval=1)
        memory = psutil.virtual_memory().percent
        disk = psutil.disk_usage('/').percent
        str_to_send_back = "{} {} {}".format(cpu, memory, disk).strip()
        str_to_send_back = str_to_send_back.encode()
        str_to_send_back = encrypt(str_to_send_back)
        print(str_to_send_back)

The server picks up the string and tries to decode it (at the bottom of this code snipper):

class server:
    command='cd %temp% && cd' # Necessary to pull client temp directory path
    run_client_script = 'cd %temp% && python client.py' # To run client script

    def __init__(self, client_ip, cliet_port, username, password):
        self.client_ip = client_ip
        self.cliet_port = cliet_port
        self.username = username
        self.password = password
        self.ssh = ssh(self.client_ip, self.username, self.password)

    def upload_script_and_get_stats(self):
        try:
            # Built temp directory path for client machine
            client_temp_dir_location = str(self.ssh.send_command(self.command)).strip()

            # Client script file name
            file_name = "\\client.py"

            # Build absolute path of source file
            source_file_location = os.path.dirname(os.path.abspath(__file__)) + file_name

            # Build absolute path of destination file
            destination_file_location = client_temp_dir_location + file_name

            # Upload client script
            ftp_client = self.ssh.open_sftp(source_file_location, destination_file_location)

            # Run client script and get result
            result = self.ssh.send_command(self.run_client_script)

            # SERVER DECODES STRING HERE
            result = self.decrypt(result)
            return str(result)


        except Exception as e:
            print("Oops this error occured in transfer_files_to_client(): " + str(e))
        finally:
            self.ssh.close()

    def decrypt(self, ciphertext):
        try:
            print(ciphertext)

            obj2 = AES.new(b'This is a key123', AES.MODE_CFB, b'This is an IV456')
            return obj2.decrypt(ciphertext)
        except Exception as e:
            print("FDSDSFDSF: "+str(e))

However, the decode method in server throws this error:

FDSDSFDSF: Only byte strings can be passed to C code

However what gets passed to the method is this:

b'\xb5\xf7\xbc\xd5\xfc\xff;\x83\xd3\xab\xb1mc\xc3'

which is already encoded.

Seif
  • 701
  • 4
  • 13
  • 32
  • 2
    Add which major version of Python are you using to the question and `print(type(ciphertext))` to `decrypt` as well. I suspect that your data is not what you think it is. Also usually it's better to include the full traceback in the question, instead of just the string representation of the exception object. – Ilja Everilä Jan 02 '18 at 21:49
  • It returned str. I put it inside bytes like this: print(bytes(ciphertext, encoding = "utf8")) but now it returns: b"b'\\xb5\\xf2\\x81\\x89\\x99\\xe9_\\xbd\\xbb\\x84\\xec\\xc3r\\xa4'\r\n" – Seif Jan 02 '18 at 21:56
  • It might be slightly more informative if you don't capture the exception and format it; do you know for sure it's failing at `obj2.decrypt` or at `AES.new`? If `print(ciphertext)` is *printing* `b'\x...'` it might *actually* be a string `"b'\\x...'"` Try `print(repr(ciphertext))`. – Nick T Jan 02 '18 at 22:02
  • @NickT it prints this: 'b"\\xb5\\xf4\\xe1\'\\x18=\\xb3cJ\\xfe\\xd3u\\x9f\\xd6"\r\n' – Seif Jan 02 '18 at 22:08

1 Answers1

2

Your ciphertext is a string that contains the string representation of a bytes object. I assume your server and client are running on Python 3 and so

print(str_to_send_back)

in the client just prints the representation of the bytes object to standard output. Try using some string friendly encoding for your bytes, such as base64:

from base64 import b64encode

def collect_stats():
    try:
        ...
        # str_to_send_back is actually bytes
        # Decode the bytes that contain ASCII text for printing
        print(b64encode(str_to_send_back).decode('ascii'))

and decode in the receiving end:

from base64 import b64decode

def decrypt(self, ciphertext):
    # Removed the over eager "exception handling". The traceback is a
    # lot more informative and useful. Add *specific* exception handling
    # as necessary
    aes = AES.new(b'This is a key123', AES.MODE_CFB, b'This is an IV456')
    return aes.decrypt(b64decode(ciphertext))
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127