Can't pickle an RSA key to send over a socket - python

I have a list with a public key and a username that I want to send over a socket.
I found
how to send an array over a socket in python but using pickling won't work either.
My code:
private_key = generateRSA()
public_key = private_key.public_key()
host = ''
port = 8000
username = sys.argv[1]
mySocket = socket.socket()
mySocket.connect((host, port))
dataToSend = [public_key, username.encode()]
dataSend = pickle.dumps(dataToSend)
mySocket.send(dataSend)
The error in the console says
dataSend = pickle.dumps(dataToSend)
_pickle.PicklingError: Can't pickle <class '_cffi_backend.CDataGCP'>: attribute lookup CDataGCP on _cffi_backend failed
The key was generated with the cryptography library.

You are trying to send a RSAPublicKey instance, but this is a data structure managed by SSL, not Python. Because you interact with it through a CFFI proxy, you can't pickle one of these.
You'll need to pick a key serialization format to send it instead. You could convert to PEM, for example:
from cryptography.hazmat.primitives import serialization
pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
The above would export your key to a string value you could then convert to bytes and send over the socket directly. The other side would load the key from that string again.
Note that the above uses no encryption whatsoever. Anyone intercepting the traffic over that socket would be able to read your public key. That may or may not be a problem for your application.

Related

socket error in python 2.7, sending public rsa key to client

I'm programming a client-server communication encrypted with RSA, using tcp sockets. I generate public and private keys, but when I want to exchange the public keys between client and server I get this error:
TypeError: must be convertible to a buffer, not PublicKey
This is server code:
import socket
import rsa
print "Generating keys"
(public, private) = rsa.newkeys(1024, poolsize=2)
print "Keys generated."
tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
tcpSocket.bind(("0.0.0.0", 1025))
tcpSocket.listen(1)
print "Waiting for client..."
(client, (ip, port)) = tcpSocket.accept()
print "Connection received from: ", ip
client.send(public) #This is where I get the error
I've tried with this line too:
client.send(str(public))
With this I can send the public key, but then I can't use it to encrypt data (because now the public key is a string).
Thank you for your help !
You can use Pickle or cPickle:
import cPickle
to_send=cPickle.dumps(the_key)
sock.send(to_send)
And then unpickle it:
import cPickle
s=sock.recv()
key=cPickle.loads(s)

Sending an array over UDP connection

I want to send an array using a UDP connection. When I use the sendto function, it complains that it must be a string. Is there any way around this?
Thanks
You must serialize your data (in this case is an array) before sending it. Then in receiver, you will deserialize to get the original data.
You can do it in Python, using pickle or cPickle module:
import cPickle as p
# Sender
data_str = p.dumps(array)
sock.sendto(data_str, addr)
# Receiver
data,addr = sock.recvfrom(buf)
data_origin = p.loads(data)

decrypt ssl encrypted data in python

I'm analyzing a packet capture with python using dpkt. The application layer is encrypted with ssl. I'd like to decrypt the ssl data (i.e., the tcp payload). I have the private key, so I should be able to use the key to decrypt the data. Here's my script:
#!/bin/python
import sys
import dpkt
def main():
if not len(sys.argv) == 2:
print "need a pcap file"
return 1
filename = sys.argv[1]
f = open(filename)
pcap = dpkt.pcap.Reader(f)
framenum = 1
for ts, buf in pcap:
if framenum == 123:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
tcp = ip.data
ssl = tcp.data
# decrypt ssl
framenum += 1
if __name__ == '__main__':
sys.exit( main() )
What can I put in place of that "decrypt ssl" comment to get the decrypted ssl bytes? I'm guessing there should be some library that can do this for me, but all my searches for ssl and python give information about writing socket programs that can receive ssl connections. I'm not interested in that. Rather, I need to decrypt data that is encrypted with ssl.
Thanks!
You're not likely going to find a ready-made library to do this. Decrypting from a packet dump is rather involved, and I believe the best featured tool right now is still Wireshark.
Note that you will also need to have the entire TLS session captured, from the handshake onward. Also, if the connection used an ephemeral mode which offers forward secrecy (anything with DHE or ECDHE), the data cannot be decrypted.

Public key not recognized

I am trying to export a public key from openssl using python. I have the actual key information transferred to the client from the server but the PEM encoding is not transferred so the key on the client is useless. I basically send the public key using send all in python but unfortunately this does not send the PEM encoding. Does anyone know how to transfer the encoding?
I didn't know that the encoding would not transfer along with the key.
THe code where the string is read in
import socket
import M2Crypto as m2c
import os
max_transfer_block = 1024
server_addr = "10.1.1.2"
dest_port = 3333
listen_port = 8888
client_addr = "10.1.1.3"
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.connect((server_addr, dest_port))
#receive the public key from the server
keysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
keysocket.bind((client_addr, listen_port))
keysocket.listen(1)
conn, client_addr = keysocket.accept()
print 'connected by', client_addr
data = conn.recv(max_transfer_block)
#FILE = m2c.RSA.save_pub_key(data, "serverPubKey.pem")
FILE = open("sPub.pem", "w")
FILE.write(data)
keysocket.close()
#transfer encrypted file
key = m2c.RSA.load_pub_key('serverPubKey.pem')
FILE = open("test.txt", "r")
data = FILE.read()
encrypted = key.public_encrypt(data, m2c.RSA.pkcs1_padding)
mysocket.sendall(encrypted)
mysocket.close()
When I use the line key = m2c.RSA.load_pub_key('serverPubKey.pem') I get an error telling me that there is no starting point.
raise RSAError, m2.err_reason_error_string(m2.err_get_error()) M2Crypto.RSA.RSAError: no start line
I have figured out that this is because there is not in PEM format. Unfortunately, I don't know how to put it in that format.
The mistake was that the public/private key pair needs to be created from the same wrapper. What I mean by this is that not all key pairs are the same. My specific problem was that Openssl and the M2Crypto instances of key pairs were not in the same underlying format. Thus creating keys with Openssl and then trying to use M2Crypto to use the keys was wrong. The lesson from all of this is to not import keys from other wrappers. If you do, make sure that they are in the same underlying format like ASCII or Unicode before trying to use them.

Sending and Receiving arrays via Sockets

Is it possible to send an array through UDP Sockets using Python? I am using Python 2.5 and trying to send a simple array but it's not working. It can send the array successfully but when I try to print it with an item of the array the program crashes. I'm not sure what the error is as I take the precaution of converting the data into an array but it's not working. Hope I explained the problem as clearly as possible. I would appreciate the help!
# Client program
from socket import *
import numpy
from array import*
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)
def_msg = "===Enter message to send to server===";
print "\n",def_msg
a = array('i',[1,3,2])
# Send messages
while (1):
data = raw_input('yes or now')
if data!= "yes":
break
else:
if(UDPSock.sendto(a,addr)):
print "Sending message"
# Close socket
UDPSock.close()
# Server program
from socket import *
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket and bind to address
UDPSock = socket(AF_INET,SOCK_DGRAM)
UDPSock.bind(addr)
# Receive messages
while 1:
data,addr = UDPSock.recvfrom(buf)
L = eval(data)
if not data:
print "Client has exited!"
break
else:
print "\nReceived message '", L[1],"'"
# Close socket
UDPSock.close()
eval is doing something completely different than what you think.
To send data over network, you need to serialize it into an array of bytes, then deserialize it back. In Python, serialization of most objects can be done via pickle module:
if (UDPSock.sendto( pickle.dumps(a), addr)):
Deserialization:
data,addr = UDPSock.recvfrom(buf)
L = pickle.loads(data)
print repr(L) # prints array('i', [1, 3, 2])
I would personally use tostring and fromstring since the built-in serialization methods are many times faster and pickle may not support NaN, Inf and other undefined values.
You're trying to send a python object through a socket, it is normal that it doesn't work, you can't send objects in a socket, objects are not data, they are the representation of some data in a given programming language. You need to "translate" your object to data and re-create the object from the data on the other socket's side. One way to do this would be with the pickle module.
On the client side, you "pickle" the object:
data = pickle.dumps(my_array)
And on the server side, you "unpickle" the received data:
my_array = pickle.loads(received_data)
You could try to pickle the array. Pickle is a python library to en- and decode python objects. It is able to do much more, but it is definitely sufficient to fulfill your task:
on the sender side you pickle the object to a string:
pickled_string = pickle.dumps(a)
on the receiver side you unpickle the object:
a = pickle.loads(received_string)
# a is now your sent array
It has been a while since this question was asked, but I thought it's worth sharing the jsonsocket library. It makes it really easy to send strings, lists and dictionaries over sockets. It can handle big amounts of data efficiently. And you don't need to do any manual serialization/deserialization. Under the hood, it serializes the data as JSON strings on the client, and deserializes it on the server.
If you don't need UDP specifically, try zmqObjectExchanger (https://github.com/ZdenekM/zmq_object_exchanger). It wraps pickle and zmq to transfer python objects over TCP.

Categories