AES encrypted File transfer over TCP socket; padding issue - python

I'm trying to do a file transfer using encrypted TCP socket with AES 256.
If I transfer a file without encryption, it works fine.
If I send small commands (such as 'ipconfig') to the client or server, the encryption works fine.
No matter the file size is, I keep receiving the following error message:
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
File "/usr/lib/python2.6/base64.py", line 76, in b64decode
raise TypeError(msg)
TypeError: Incorrect padding
My function for encoding and decoding is the following (the hat variable is the message):
def AESENC(hat,typ):
BLOCK_SIZE = 32
PADDING = '{'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
secret = '01234567890123456789012345678912'
IV = 'wir&/>H54mgd9a";'
cipher = AES.new(secret,AES.MODE_CFB,IV)
if typ == 0:
encoded = EncodeAES(cipher, hat)
return encoded
else:
decoded = DecodeAES(cipher, hat)
return decoded
Client side
if os.path.exists(df):
print ' found the file '
f = open(df, 'rb')
packet = f.read(1024)
while packet != '':
s.send(AESENC(packet,0))
s.send( AESENC('123XXX',0) )
s.send('123XXX')
f.close()
Server side
f = open('/root/Desktop/Transfer.mp3','wb')
while True:
bits = AESENC ( conn.recv(1024) , 1 )
while (bits):
f.write(bits)
bits = AESENC ( conn.recv(1024) , 1 )
if bits.endswith('123XXX'):
print '[+] Transfer completed '
break
f.close()
break
return
Does anybody know how to fix this?

Apologies for the misunderstanding of your sample code, and thank you for adding the server and client calls!
Please note that the error message that you're getting is unrelated to the encryption. You can read the relevant part of the base64.py library: the error message indicates that the base64 data is not valid. In particular, it's not properly padded at the end.
With the additional call site information, I believe the problem is that you're encrypting and then separately encoding each 1024 byte block of the data on the client. Then, on the server, you're reading 1024 bytes from the network and trying to decode it. However, base64-encoding will increase the length of the original data, so what you'll read will only be the first 1024 bytes of the encoded form, which will be a truncated base64 message (hence improperly padded).
As for how to solve it, a base64 message needs to be decoded all as one piece. So you either need to calculate how much data to read from the network to get a complete encoded block (a calculation that you can do reliably except for the possibly short last packet, since the base64 length is always (length + 2) / 3 * 4), encode the entire data stream at once (which is likely a problem due to memory use if you want to handle arbitrary-sized files), or define your network protocol so that the server can tell that it's seen a complete block that can be decoded with base64.

Related

Size of PKCS#7 padded string changes after AES encryption

I am trying to implement some mechanism in the tor network for educational purposes. The mechanisem that I am trying to implement is that the messages need to be in a fixed size of 512 bytes before they are sent over the network. but when I am padding some string with PKCS#7 to be 512 bytes, after encryption it changes to be 750 bytes for some reason. Do someone know why the encryption of the speaciel characters from the padding changes the length of the message?
This is my main code
def main():
data = "A" * 600
cells = build_message(data) # divided the data to be messages of 512 bytes
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("127.0.0.1", 4000))
tls = establish_tls_connection(sock, "client") # establishing a tls session
for cell in cells:
print(len(str(cell))) # printing the len message before encrypting
encrypted = tls.encrypt(str(cell))
print(len(encrypted[0])) # printing the len message after encrypting
This is an example of a padded before encryption
{
'sequence': 2, 'next_hop_ip': '127.0.0.1',
'next_hop_port': 443, 'padded': 1, 'payload':
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî
îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî
îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî
îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî'
}
As you can see I have a lot unprintable characters in the message, Please tell me if you need me to provide any more parts of my code.
Thank you.

Unable to transfer file using Sockets on different computers

I recently wrote a code for a file transfer in Python. Sockets connect fine when I connect them from different terminals on the same system. But the same doesn't seem to work when I connect them from different computers which are connected over the same Wifi network.
Here's the server code:
import os
import socket
# Creating a socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("192.164.X.X",2222))
sock.listen(5)
print("Host Name: " , sock.getsockname())
# Accepting the connection
client , addr = sock.accept()
# Getting file details
file_name = input("File Name:")
file_size = os.path.getsize(file_name)
# Sending file name and details
client.send(file_name.encode())
client.send(str(file_size).encode())
# Opening file and sending data
with open(file_name,"rb") as file:
c = 0
while c <= file_size:
data = file.read(1024)
if not (data):
break
client.sendall(data)
c += len(data)
# closing the socket
sock.close()
Here's my client code:
import os
import socket
host = input("Host Name: " )
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Trying to connect to socket
sock.connect((host,2222))
print("Connected Successfully")
# send file details
file_name = sock.recv(100).decode()
file_size = sock.recv(100).decode()
with open("./rec/" + file_name , "wb") as file:
c = 0
while c <= int(file_size):
data = sock.recv(1024)
if not (data):
break
file.write(data)
c += len(data)
sock.close()
When I try to connect The client From a different computer I get this error :
while c <= int(file_size):
ValueError: invalid literal for int() with base 10: '3hi\n'
The file I am trying to transfer has a single word 'hi'.
File transfer works correctly from different terminals on same machine. But the same doesn't work on different computers which are connected over the same wifi network.
I understand the error (trying to convert string to int) but I don't WHY it's happening and how to fix it.
Your server code is sending a single TCP packet containing the content of multiple client.send() calls. This is commonly known as "corking", and can usually be disabled (depending on your OS) using the socket.TCP_NODELAY socket option after accepting the connection.
client, addr = sock.accept()
client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
This is however not guaranteed to work, and depends on your OS and OS settings.
The real solution would be to create a more robust protocol and avoid relying on data being sent in different packets. In fact, this is the only sane way of implementing any protocol based on TCP. Never rely on data being split in packets in a specific way.
Decide a fixed size for encoding and sending lengths, then do the following on the server:
Send a length (of fixed size, for example 8 characters or 8 bytes, or whatever you would like) for the file name.
Send the filename.
Send the file size (again of fixed size).
Send the file contents.
While on the client:
Receive exactly 8 bytes and decode the length.
Receive exactly length bytes for the filename.
Receive exactly 8 bytes and decode the file size.
Receive exactly size bytes for the file contents.
Most importantly, note that the .recv() method of sockets can return less than the requested amount (you seem to already know that), so whatever kind of receiving operation you need to do, you will need to accumulate data in a loop until you have received the expected amount, for example:
expected = 100
data = b''
while len(data) < expected:
data += sock.recv(expected - len(data))

How to check if socket connection is working and buffering or is the request incorrect?

I have been trying to figure this out and can't seem to wrap my head around it.
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server = '192.168.1.7'
port = 8000
buffer_size = 4096
request = '1|gkdgdfg49|sdfsdfsd*|sdsfsf*|'+server
request = request.encode()
s.connect((server,port))
s.send(request)
x = s.recv(buffer_size)
The documentation for the server side is:
https://www.sharekhan.com/Upload/General/TradeTigerAPIForClient.pdf
The log of api server shows:
[I] "API Client Socket Connected with error Code=0"2018-09-22 16:07:23.555+05:30
[I] "Hurraay You have Connected."2018-09-22 16:07:23.555+05:30
[I] "Received Bytes Count = 49 Data Length = 1801944113 Thread State = Background, WaitSleepJoin , Queue Count = 0"2018-09-22 16:07:23.555+05:30
[I] "API Client Request Data Length 1801944113 bytes needs to read"
2018-09-22 16:08:21.984+05:30
[I] "Received Bytes Count = 49 Data Length = 1801944113 Thread State = Background, WaitSleepJoin , Queue Count = 0"
2018-09-22 16:08:21.984+05:30
[I] "API Client Request Data Length 1801944113 bytes needs to read"|Reserved = |
Is the request correct? Is the data being transferred?
If I rerun
s.send(request)
x = s.recv(buffer_size)
Nothing happens. The interpreter is stuck at running the above two lines.
I would appreciate any help. Very new to `sockets and the documentation is not very helpful.
As I pointed out in your other question, this is a binary protocol.
You're sending it ASCII text. Note that big number (1801944113), when interpreted as text, is equal to 'kg|1'. This is (the big-endian ordering of) the first four characters you sent it. In other words, it's taken the first four bytes you sent it, interpreted them as a binary value, and is now using it as the message length value -- which is obviously all wrong.
You need to use the python struct module's pack and unpack methods to encode and decode binary values to build up your buffer.
That would look something like this:
import struct
trans_code = 1 # LOGIN
login_id = b'MyName'
mpassword = b'MyPass'
tpassword = b'MyTradingPass'
my_ip = b'192.168.1.31' # No idea what the point of this is
reserved = b''
msg_length = 196
msg_buffer = struct.pack("!IH30s20s20s20s100s", msg_length, trans_code,
login_id, mpassword, tpassword, my_ip, reserved)
assert len(msg_buffer) == msg_length
print("Login request to send '{}'".format(msg_buffer))
You will need to learn to use the struct module. It's well-specified in the python documentation.
Your results (in particular that big number) establish that the server is expecting numeric fields to be encoded in big-endian byte order (AKA "network byte order").

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.

Client and Server unable to exchange data python

I'm using python 3.3.this is Server.py.Everything is fine both server and client are able to connect
something might be wrong in here 'tcpcli.send('[%s]%s'%(bytes(ctime(),'utf-8'),data))'.help me out
from socket import *
from time import ctime
HOST=''
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcp=socket(AF_INET,SOCK_STREAM)
tcp.bind(ADDR)
tcp.listen(5)
while True:
print('waiting for connection')
tcpcli,addr=tcp.accept()
print('...connected from:',addr)
while True:
data=tcpcli.recv(BUFSIZ)
if not data:
break
tcpcli.send('[%s]%s'%(bytes(ctime(),'utf-8'),data))
tcpcli.close()
tcp.close()
This is CLient.py
from socket import *
HOST='127.0.0.1'
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpcli=socket(AF_INET,SOCK_STREAM)
tcpcli.connect(ADDR)
while True:
data=input('>')
if not data:
break
tcpcli.send(data)
data=tcpcli.recv(BUFSIZ)
if not data:
break
print (data.decode('utf-8'))
tcpcli.close()
When i'm running both they are working fine except I'm unable to send any data from client.
I'm getting this error message.
tcpcli.send(data)
TypeError: 'str' does not support the buffer interface
You are using Python3. This means that, when using the CLI, input() will return a str object (equivalent to python2 unicode). It contains an internal representation of the unicode codepoints of the characters you entered. To send the data over a byte stream interface (such as pipes, sockets, …), you have to convert it to a bytes object. This is easily done by picking an encoding, such as UTF-8, and doing something like this:
data_raw = data.encode("utf-8")
tcpcli.send(data_raw)
You will have to adapt your servers code similarily, by first decoding the data you received from the client and reencoding it after you did string operations on it:
data_decoded = data.decode("utf-8")
reply = '[%s]%s' % (ctime(), data_decoded)
tcpcli.send(reply.encode("utf-8"))
You are building unicode strings, not byte strings, and the socket interface doesn't support unicode strings. You'll need to encode the result of the string interpolation:
tcpcli.send(bytes('[%s]%s' % (ctime(),data), 'utf-8'))

Categories