python写的代理对socket通讯加密出错


正在学习写的网页代理服务器在对中间数据加密时出现错误,浏览器接收资源不全,
用的 SocketServer 模块,
client中:


 python


 #!/usr/bin/env python2
# conding=utf-8
import sys
import socket
from SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandler
import struct
import select
import logging
from AesEncrypt import AesEncrypt
import hashlib

def encrypt(data):
    newencrypt = AesEncrypt()
    psw = 'admin'
    salt = '123456'
    newencrypt.md5(psw,salt)
    return newencrypt.encrypt(data)

def decrypt(data):
    newdecrypt = AesEncrypt()
    psw = 'admin'
    salt = '123456'
    newdecrypt.md5(psw,salt)
    return newdecrypt.decrypt(data)

def sendall(sock,data):
    length = 0
    while True:
        result = sock.send(data[length:])
        if result < 0:
            return result
        length += result
        if length == len(data):
            return length

class Log():
    def __init__(self):
        self.logger = logging.getLogger('log')
        self.logger.setLevel(logging.DEBUG)
        f = logging.FileHandler('./log')
        f.setLevel(logging.DEBUG)
        self.logger.addHandler(f)

    def log(self, data):
        self.logger.info(data)

class Server(ThreadingMixIn,TCPServer):pass

class Socks5Server(StreamRequestHandler):
    def handleData(self, source, dest):
        try:
            while 1:
                active, w, x= select.select([source, dest], [], [], 5)
                if not active:
                    break
                if source in active:
                    data = source.recv(4096)
                    if len(data) <= 0:
                        break
                    data = encrypt(data)
                    re = sendall(dest,data)
                    #re = dest.send(data)
                    if re < len(data):
                        raise Exception('Failed to send all data')
                if dest in active:
                    data = dest.recv(4096)
                    if len(data) <= 0:
                        break
                    data = decrypt(data)
                    re = sendall(source,data)
                    #re = source.send(data)
                    if re < len(data):
                       raise Exception('Failed to send all data')
        finally:
            self.log.log('closed')
            source.close()
            dest.close()

    def handle(self):
        self.log = Log()
        socks = self.connection
        socks.recv(262)
        socks.send("\x05\x00")
        data = self.rfile.read(4)
        #print data
        mode = ord(data[1])
        if mode !=1:
            logging.warn('mode !=1')
            return
        addrtypr = ord(data[3])
        addr_to_send = data[3]
        if addrtypr == 1:
            addr_ip = self.rfile.read(4)
            addr = socket.inet_ntoa(addr_ip)
            addr_to_send += addr_ip
        elif addrtypr == 3:
            addr_len = self.rfile.read(1)
            addr = self.rfile.read(ord(addr_len))
            addr_to_send += addr_len +addr
        else:
            logging.warn('addr_type not support')
            return
        addr_port = self.rfile.read(2)
        addr_to_send += addr_port
        port = struct.unpack('>H', addr_port)
        reply = "\x05\x00\x00\x01"
        reply += socket.inet_aton('0.0.0.0') + struct.pack('>H', 2222)
        self.wfile.write(reply)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)
        sock.connect(('127.0.0.1', 1083))
        sock.send(addr_to_send)
        self.handleData(socks, sock)
        logging.info('connecting %s:%s'%(addr,port[0]))
if __name__=="__main__":
    HOST, PORT="localhost", 8088


    try:
        server = Server((HOST, PORT), Socks5Server)

        server.serve_forever()
    except KeyboardInterrupt:
        server.shutdown()
        sys.exit()

server中:


 python


 #!/user/bin/env python2
# conding=utf-8

from AesEncrypt import AesEncrypt
from SocketServer import StreamRequestHandler, ThreadingMixIn, TCPServer
import socket
import struct
from select import select
import logging
import hashlib

def encrypt(data):
    newencrypt = AesEncrypt()
    psw = 'admin'
    salt = '123456'
    newencrypt.md5(psw,salt)
    return newencrypt.encrypt(data)
def decrypt(data):
    newdecrypt = AesEncrypt()
    psw = 'admin'
    salt = '123456'
    newdecrypt.md5(psw,salt)
    return newdecrypt.decrypt(data)

def sendall(sock,data):
    length = 0
    while True:
        result = sock.send(data[length:])
        if result <0:
            return result
        length += result
        if length == len(data):
            return length

class ServerThread(ThreadingMixIn, TCPServer):
    pass

class Server(StreamRequestHandler):
    def handle(self):
        socks = self.connection
        addrtype = ord(socks.recv(1))
        if addrtype == 1:
            addr = socket.inet_ntoa(self.rfile.read(4))
        elif addrtype == 3:
            addr = self.rfile.read(ord(socks.recv(1)))
        else:
            logging.warn('addr type not support')
            return


        port = struct.unpack('>H', self.rfile.read(2))
        logging.info('connecting %s:%d'%(addr,port[0]))
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)
        client.connect((addr, port[0]))
        try:
            while 1:
                active, w, x = select([socks, client], [], [])

                if not active:
                    break

                if socks in active:
                    data = socks.recv(4096)
                    if len(data)<= 0:
                        break
                    data = decrypt(data)
                    re = sendall(client,data)
                    #re = client.send(data)
                    if re < len(data):
                        raise Exception('Failed to send all data')
                if client in active:
                    data = client.recv(4096)
                    if len(data) <= 0:
                        break
                    data = encrypt(data)
                    re = sendall(socks,data)
                    #re = socks.send(data)
                    #undata = decrypt(data)
                    if re < len(data):
                        raise Exception('Failed to send all data')
        finally:
            print 'closed!!!'
            client.close()
            socks.close()


if __name__== "__main__":
    HOST, PORT="localhost", 1083


    server = ServerThread((HOST, PORT), Server)

    server.serve_forever()

AesEncrypt.py:


 python


 # coding=utf-8

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import hashlib


class AesEncrypt(object):

    def md5(self, psw, salt):
        self.hasli = salt + psw
        self.MD5 = hashlib.md5(self.hasli).hexdigest()
        self.KEY = self.MD5[0:16]
        self.IV = self.MD5[16:]

    def encrypt(self, data):
        length = 16
        count = len(data)
        if count == 0:
            return data
        elif count < length:
            add = (length - count)
            data = data + ('$' * add)
        elif count > length:
            if count % length == 0:
                data = data
            else:
                add = (length - (count % length))
                data = data + ('$' * add)
        obj = AES.new(self.KEY, AES.MODE_CBC, self.IV)
        cipherdata = obj.encrypt(data)
        #cipherdata = b2a_hex(cipherdata)
        return cipherdata

    def decrypt(self, cipherdata):
        if len(cipherdata) == 0:
            return cipherdata
        else:
            obj = AES.new(self.KEY, AES.MODE_CBC, self.IV)
            #data = a2b_hex(cipherdata)
            data = obj.decrypt(cipherdata)
            data = data.rstrip('$')
            return data

encrypt()是加密函数,decrypt()解密,用的是AES加密,因为不足16位倍数时需要补位,但解密后会删掉补位的字符。
开始代理后,结果网页加载不全,一般只能打开一部分资源,大部分加载不出来(如不能获取css,js,图片等等,但都是随机会少一些资源。)。
因为对TCP协议不是很了解,用wireshark抓包分析也看不出什么,
比较收到、发出的数据包的md5值也是一样,不知道哪出了问题,新人求指点啊~~~
sockcs.sendall() 也是使用过,有时候会爆出error: [Errno 104] Connection reset by peer

代理 python aes socket

Lua2z 10 years, 7 months ago

代码看完了,结论是:你不懂加密。

  • 你用了 CBC 模式,但是每次均使用新的实例
  • 你的 IV 从来不变化。这样还不如用 ECB 模式。反正早不安全了不是么

你这样做的结果除了不安全之外,你必须 保证每次加密和对应的解密的数据是同一段数据 ,但是你没有做这种保证。经常会出现 你加密了4096字节数据发过去,对方收到了2048字节就去解密,后边的2048字节使用新初始化的对象进行解密 。所以数据才会不正确。

写网络程序的时候要注意 不完整的 recv 和 send(实际处理的数据量小于预期) 。而写加密程序的时候要注意 很可能 根本不懂 加密 (这里有四个链接哦)。

建议使用现成的 TLS/SSL。

MJ蓝猫党 answered 10 years, 7 months ago

Your Answer