Search code examples
pythonsocketspython-3.xencryptionpycrypto

Python 3 - Socket Chat Encryption with PyCrypto gives UnicodeDecodeError


I am trying to setup a socket chat with encryption in Python 3, but when decoding UTF-8 it gives an error.

Here is the code:

Client:

from Crypto.Cipher import AES 
from Crypto import Random 
import socket, sys
host = 'localhost'
port = 5558
IV = Random.new().read(16) 
c = AES.new('abcd1234efgh5678', AES.MODE_CFB, IV) 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
data = 'hey'.encode('utf-8') # 1
data = c.encrypt(data) # 2
s.sendall(data)

Server:

from Crypto.Cipher import AES 
from Crypto import Random 
import socket, sys
host = ''
port = 5558
IV = Random.new().read(16) 
c = AES.new('abcd1234efgh5678', AES.MODE_CFB, IV) 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(10)
sock, addr = s.accept()
data = sock.recv(512)


data = c.decrypt(data) # 1
data = data.decode('utf-8') # 2
print(data)

After running these programs the server gives this error:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa5 in position 0: invalid start byte

So, I tried changing 'utf-8' in the Server code to 'latin-1' and it instead kept printing different unicode characters each time the program was run. I then swapped the 2 lines marked with comments in both the client and server, and of course it gave this error:

AttributeError: 'bytes' object has no attribute 'encode'

I have tried Google but all of the programs that use PyCrypto use Python 2, not 3. Eg. Encrypt & Decrypt using PyCrypto AES 256

http://eli.thegreenplace.net/2010/06/25/aes-encryption-of-files-in-python-with-pycrypto/


Solution

  • apart from the fact that your code above uses // as comments (should be #), i ran the code below (removed everything socket) and found the error: you re-initialize the IV before decrypting. this way you will not get the original value back - just some gibberish that may not be decodable in utf-8.

    you will have to send the IV to the server (How to communicate AES initialization Vector to client for hybrid cryptosystem).

    from Crypto.Cipher import AES 
    from Crypto import Random 
    
    # CLIENT -----------------------------------------
    IV = Random.new().read(16) 
    c = AES.new('abcd1234efgh5678', AES.MODE_CFB, IV) 
    data = 'hey'.encode('utf-8') #  1
    data = c.encrypt(data) #  2
    
    
    # SERVER -----------------------------------------
    
    # THIS IS WHERE YOUR CODE GOES WRONG!
    # IV = Random.new().read(16) 
    
    c = AES.new('abcd1234efgh5678', AES.MODE_CFB, IV) 
    
    data = c.decrypt(data) # 1
    data = data.decode('utf-8') # 2
    print(data)