Пример #1
0
    def begin_auth(self):
        # Deal with the beginning authentication
        try:
            self.read += self.recv(2048)
            if self.split in self.read:
                authdata = self.read.split(b'\r\n')
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    verify = self.ctl.serverpub.verify(
                        self.ctl.main_pw, (int(signature, 36), None))
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    try:
                        self.cipher = AESCipher(
                            self.ctl.clientpri.decrypt(authdata[1]),
                            self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(
                                b"2AUTHENTICATED" + authdata[2] +
                                repr(self.ctl.server_recv_max_idx[
                                    self.i]).encode()) + self.split)
                        self.send_legacy(
                            eval(authdata[3].rstrip(
                                self.split).decode('utf-8')))
                        self.read = None
                    except ValueError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()
Пример #2
0
 def __init__(self, process_name=None):
     self.process_name = self.__class__.__name__ if process_name is None else process_name
     with open(f"{WORK_DIR}/config.yaml", 'r') as stream:
         config = yaml.safe_load(stream)
     self.config = config
     self.config['bot']['token'] = AESCipher('1029384756123456').decrypt(
         self.config['bot']['token'])
     self.logger = logger_init(self.process_name,
                               config['logging']['level'].upper())
Пример #3
0
    def begin_auth(self):
        # Deal with the beginning authentication
        try:
            self.read += self.recv(2048)
            if self.split in self.read:
                authdata = self.read.split(b'\r\n')
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    verify = self.ctl.serverpub.verify(
                        self.ctl.main_pw, (int(signature, 36), None))
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    try:
                        self.cipher = AESCipher(
                            self.ctl.clientpri.decrypt(authdata[1]), self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(b"2AUTHENTICATED" + authdata[2] +
                                                repr(
                                                self.ctl.server_recv_max_idx[self.i]).encode()
                                                )
                            + self.split
                        )
                        self.send_legacy(
                            eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except ValueError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()
Пример #4
0
    def begin_auth(self):
        # Deal with the beginning authentication
        self.read = b''
        try:
            self.read += self.recv(770)
            if len(self.read) >= 770:
                self.read = self.read[:770]
                blank = self.read[:512]
                # TODO: fix an error in int(blank,16)
                if not self.ctl.remotepub.verify(self.ctl.str, (int(blank, 16), None)):
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    # self.send(self.ctl.localcert.encrypt(pyotp.HOTP(self.ctl.localcert_sha1)) + self.splitchar)
                    self.cipher = AESCipher(
                        self.ctl.localcert.decrypt(self.read[512:768]), self.ctl.str)
                    self.full = False
                    self.idchar = self.read[768:770].decode('utf-8')
                    self.ctl.newconn(self)
                    logging.debug(
                        "Authentication succeed, connection established")
                    # send confirmation
                    self.send(
                        self.cipher.encrypt(b"2AUTHENTICATED" + self.read[768:770]) + self.split)
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception:
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()
Пример #5
0
import json
import os
import base64
import logging
import OpenSSL.crypto
from tornado import web, gen
from OpenSSL.crypto import load_certificate_request, FILETYPE_PEM
from tornado_mysql import pools
from config import *
from gencert import gencert
from revoke import revokeFromCert, revokeFromSerial
from common import jsonMessage, gencrl, AESCipher, paramFormat, logRequestInfo

# 使用aes-256-cfb算法解密csr_body,如果是解密失败(非法请求)则后续验证肯定出错
aesCipher = AESCipher(VALIDATE_SECRET)


class GetCACertHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        # 打印请求者日志
        logRequestInfo(self.request)
        cacert_path = os.path.join(CA_ROOT, CA_CERT_FILE)
        # 校验根证书是否存在
        if not os.path.exists(cacert_path):
            self.set_status(404)
            return

        # 设置http_header为pem格式的证书
        self.set_header("Content-Type", "application/x-pem-file")
        self.set_header('Content-Disposition',
Пример #6
0
class serverreceiver(asyncore.dispatcher):

    '''represent each connection with arkc-server'''

    def __init__(self, conn, ctl):
        self.ctl = ctl
        asyncore.dispatcher.__init__(self, conn)
        self.from_remote_buffer_raw = b''
        self.cipher = None
        self.preferred = False
        self.closing = False
        self.split = bytes(
            chr(27) +
            chr(28) +
            "%X" % struct.unpack('B', self.ctl.str[-2:-1])[0] +
            "%X" % struct.unpack('B', self.ctl.str[-3:-2])[0] +
            chr(31),
            "UTF-8"
        )
        self.no_data_count = 0
        self.read = b''
        self.latency = 10000
        time.sleep(0.05)  # async
        self.begin_auth()

    def ping_recv(self, msg):
        """Parse ping (without flag) and send back when necessary."""
        seq = int(msg[0])
        #logging.debug("recv ping%d" % seq)
        if seq == 0:
            raw_packet = "1" + "1" + msg[1:] + get_timestamp()
            to_write = self.cipher.encrypt(raw_packet) + self.split
            #logging.debug("send ping1")
            self.send(to_write)
        else:
            time1 = parse_timestamp(msg[1:])
            self.latency = int(time.time() * 1000) - time1
            logging.debug("latency: %dms" % self.latency)

    def handle_connect(self):
        pass

    def handle_read(self):
        """Handle received data."""

        b_close = bytes(CLOSECHAR, "ASCII")

        if self.cipher is None:
            self.begin_auth()
        else:
            read_count = 0
            self.from_remote_buffer_raw += self.recv(8192)
            bytessplit = self.from_remote_buffer_raw.split(self.split)
            for Index in range(len(bytessplit)):
                if Index < len(bytessplit) - 1:
                    b_dec = self.cipher.decrypt(bytessplit[Index])
                    # flag is 0 for normal data packet, 1 for ping packet
                    flag = int(b_dec[:1].decode("UTF-8"))
                    if flag == 0:
                        try:
                            cli_id = b_dec[1:3].decode("UTF-8")
                            seq = int(b_dec[3:9].decode("UTF-8"))
                            b_data = b_dec[9:]
                        except Exception:
                            logging.warning("decode error")
                            cli_id = None
                        if cli_id == "00":
                            if b_data == b_close:
                                logging.debug("closing connection")
                                self.closing = True
                                self.ctl.closeconn(self)
                                self.close()
                            elif seq == 50:
                                id_list = b_data.decode("UTF-8").split(',')
                            # self.ctl.server_check(id_list)
                            # Experimental function
                        else:
                            if cli_id in self.ctl.clientreceivers:
                                if b_data != b_close:
                                    self.ctl.clientreceivers[
                                        cli_id].from_remote_buffer[seq] = b_data
                                else:
                                    self.ctl.clientreceivers[cli_id].close()
                                read_count += len(b_data)
                            # else:
                            #    self.encrypt_and_send(cli_id, CLOSECHAR)
                    else:
                        # strip off type (always 1)
                        self.ping_recv(b_dec[1:].decode("UTF-8"))

                else:
                    self.from_remote_buffer_raw = bytessplit[Index]
            if read_count > 0:
                logging.debug('%04i from server' % read_count)

    def begin_auth(self):
        # Deal with the beginning authentication
        self.read = b''
        try:
            self.read += self.recv(770)
            if len(self.read) >= 770:
                self.read = self.read[:770]
                blank = self.read[:512]
                # TODO: fix an error in int(blank,16)
                if not self.ctl.remotepub.verify(self.ctl.str, (int(blank, 16), None)):
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    # self.send(self.ctl.localcert.encrypt(pyotp.HOTP(self.ctl.localcert_sha1)) + self.splitchar)
                    self.cipher = AESCipher(
                        self.ctl.localcert.decrypt(self.read[512:768]), self.ctl.str)
                    self.full = False
                    self.idchar = self.read[768:770].decode('utf-8')
                    self.ctl.newconn(self)
                    logging.debug(
                        "Authentication succeed, connection established")
                    # send confirmation
                    self.send(
                        self.cipher.encrypt(b"2AUTHENTICATED" + self.read[768:770]) + self.split)
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception:
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()

    def writable(self):
        if self.preferred:
            for cli_id in self.ctl.clientreceivers:
                if self.ctl.clientreceivers[cli_id] is None:
                    logging.warning(
                        "Client receiver %s NoneType error" % cli_id)
                    del self.ctl.clientreceivers[cli_id]
                else:
                    if len(self.ctl.clientreceivers[cli_id].to_remote_buffer) > 0:
                        return True
        else:
            return False

    def handle_write(self):
        # Called when writable
        if self.cipher is not None:
            if self.ctl.ready == self:
                written = 0
                for cli_id in self.ctl.clientreceivers:
                    if self.ctl.clientreceivers[cli_id].to_remote_buffer:
                        self.id_write(cli_id)
                        written += 1
                    if written >= self.ctl.swapcount:
                        break
            self.ctl.refreshconn()
        else:
            self.handle_read()

    def handle_close(self):
        self.closing = True
        self.ctl.closeconn(self)
        self.close()

    def encrypt_and_send(self, cli_id, buf=None, b_idx=None):
        """Encrypt and send data, and return the length sent.

        When `buf` is not specified, it is automatically read from the
        `to_remote_buffer` corresponding to `cli_id`.
        """
        b_id = bytes(cli_id, "UTF-8")
        if buf is None:
            b_idx = bytes(
                str(self.ctl.clientreceivers[cli_id].to_remote_buffer_index), 'utf-8')
            buf = self.ctl.clientreceivers[cli_id].to_remote_buffer[:SEG_SIZE]
            self.ctl.clientreceivers[cli_id].next_to_remote_buffer()
            self.ctl.clientreceivers[cli_id].to_remote_buffer = self.ctl.clientreceivers[
                cli_id].to_remote_buffer[len(buf):]
        else:
            buf = bytes(buf, "utf-8")
        self.send(self.cipher.encrypt(b"0" + b_id + b_idx + buf) +
                  self.split)
        return len(buf)

    def id_write(self, cli_id, lastcontents=None, seq=None):
        # Write to a certain cli_id. Lastcontents is used for CLOSECHAR
        sent = 0
        try:
            if lastcontents is not None and seq is not None:
                sent += self.encrypt_and_send(cli_id,
                                              lastcontents,
                                              bytes(seq, 'utf-8'))
            sent = self.encrypt_and_send(cli_id)
            logging.debug('%04i to server' % sent)

        except KeyError:
            pass
Пример #7
0
class ServerReceiver(asyncore.dispatcher):

    '''represent each connection with arkc-server'''

    def __init__(self, conn, ctl):
        self.ctl = ctl
        asyncore.dispatcher.__init__(self, conn)
        self.read = b''
        self.from_remote_buffer_raw = b''
        self.cipher = None
        self.preferred = False
        self.closing = False
        self.i = -1
        self.split = bytes(
            chr(27) +
            chr(28) +
            "%X" % struct.unpack('B', self.ctl.main_pw[-2:-1])[0] +
            "%X" % struct.unpack('B', self.ctl.main_pw[-3:-2])[0] +
            chr(31),
            "UTF-8"
        )
        self.no_data_count = 0
        self.read = b''
        self.latency = 10000
        time.sleep(0.05)  # async
        self.begin_auth()

    def ping_recv(self, msg):
        """Parse ping (without flag) and send back when necessary."""
        seq = int(msg[0])
        if seq == 0:
            raw_packet = "1" + "1" + msg[1:] + get_timestamp()
            to_write = self.cipher.encrypt(raw_packet) + self.split
            self.send(to_write)
        else:
            time1 = parse_timestamp(msg[1:])
            self.latency = int(time.time() * 1000) - time1
            logging.debug("latency: %dms" % self.latency)

    def handle_connect(self):
        pass

    def handle_read(self):
        """Handle received data."""

        b_close = bytes(CLOSECHAR, "ASCII")

        if self.cipher is None:
            self.begin_auth()
        else:
            read_count = 0
            self.from_remote_buffer_raw += self.recv(8192)
            bytessplit = self.from_remote_buffer_raw.split(self.split)
            for Index in range(len(bytessplit)):
                if Index < len(bytessplit) - 1:
                    b_dec = self.cipher.decrypt(bytessplit[Index])
                    # flag is 0 for normal data packet, 1 for ping packet
                    flag = int(b_dec[:1].decode("UTF-8"))
                    if flag == 0:
                        try:
                            cli_id = b_dec[1:3].decode("UTF-8")
                            seq = int(b_dec[3:9].decode("UTF-8"))
                            b_data = b_dec[9:]
                        except Exception:
                            logging.warning("decode error")
                            cli_id = None
                        if cli_id == "00":
                            if b_data == b_close:

                                logging.debug("closing connection")
                                self.closing = True
                                self.ctl.closeconn(self)
                                self.close()
              #               elif seq == 50:
              #                   id_list = b_data.decode("UTF-8").split(',')
                            # self.ctl.server_check(id_list)
                            # TODO: Experimental function
                        else:
                            if cli_id in self.ctl.clientreceivers_dict:
                                if seq == 30:
                                    self.update_max_idx(cli_id,
                                                        int(b_data.decode('utf-8')))
                                elif b_data != b_close:
                                    self.ctl.server_recv_max_idx[
                                        self.i][cli_id] = seq
                                    self.ctl.clientreceivers_dict[
                                        cli_id].from_remote_buffer_dict[seq] = b_data
                                    self.ctl.clientreceivers_dict[
                                        cli_id].retransmission_check()
                                else:
                                    for _ in self.ctl.server_recv_max_idx:
                                        if _ is not None:
                                            _.pop(cli_id, None)
                                    self.ctl.clientreceivers_dict[
                                        cli_id].close()
                                read_count += len(b_data)
                            # else:
                            #    self.encrypt_and_send(cli_id, CLOSECHAR)
                    else:
                        # strip off type (always 1)
                        self.ping_recv(b_dec[1:].decode("UTF-8"))

                else:
                    self.from_remote_buffer_raw = bytessplit[Index]
            if read_count > 0:
                logging.debug('%04i from server' % read_count)

    def begin_auth(self):
        # Deal with the beginning authentication
        try:
            self.read += self.recv(2048)
            if self.split in self.read:
                authdata = self.read.split(b'\r\n')
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    verify = self.ctl.serverpub.verify(
                        self.ctl.main_pw, (int(signature, 36), None))
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    try:
                        self.cipher = AESCipher(
                            self.ctl.clientpri.decrypt(authdata[1]), self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(b"2AUTHENTICATED" + authdata[2] +
                                                repr(
                                                self.ctl.server_recv_max_idx[self.i]).encode()
                                                )
                            + self.split
                        )
                        self.send_legacy(
                            eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except ValueError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()

    def send_legacy(self, idx_list):
        buf = self.ctl.server_send_buf_pool[self.i]
        for cli_id in idx_list:
            try:
                queue = buf[cli_id]
                while len(queue) and queue[0][0] <= idx_list[cli_id]:
                    queue.popleft()
                if len(queue):
                    for idx, data in queue:
                        self.encrypt_and_send(cli_id, data, idx)
            except Exception:
                pass

    def writable(self):
        if self.preferred:
            for cli_id in self.ctl.clientreceivers_dict:
                if self.ctl.clientreceivers_dict[cli_id] is None:
                    logging.warning(
                        "Client receiver %s NoneType error" % cli_id)
                    del self.ctl.clientreceivers_dict[cli_id]
                else:
                    if len(self.ctl.clientreceivers_dict[cli_id].to_remote_buffer) > 0:
                        return True
        else:
            return False

    def handle_write(self):
        # Called when writable
        if self.cipher is not None:
            if self.ctl.ready == self:
                written = 0
                for cli_id in self.ctl.clientreceivers_dict:
                    if self.ctl.clientreceivers_dict[cli_id].to_remote_buffer:
                        self.id_write(cli_id)
                        written += 1
                    if written >= self.ctl.swapcount:
                        break
            self.ctl.refreshconn()
        else:
            self.handle_read()

    def handle_close(self):
        self.closing = True
        self.ctl.closeconn(self)
        self.close()

    def encrypt_and_send(self, cli_id, buf=None, b_idx=None):
        """Encrypt and send data, and return the length sent.

        When `buf` is not specified, it is automatically read from the
        `to_remote_buffer` corresponding to `cli_id`.
        """
        b_id = bytes(cli_id, "UTF-8")
        if buf is None:
            b_idx = bytes(
                str(self.ctl.clientreceivers_dict[cli_id].to_remote_buffer_index), 'utf-8')
            buf = self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer[:SEG_SIZE]
            self.ctl.clientreceivers_dict[cli_id].next_to_remote_buffer()
            self.ctl.clientreceivers_dict[cli_id].to_remote_buffer = self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer[len(buf):]
            if cli_id not in self.ctl.server_send_buf_pool[self.i]:
                self.ctl.server_send_buf_pool[self.i][cli_id] = []
        else:
            buf = bytes(buf, "utf-8")
        tosend = self.cipher.encrypt(
            b"0" + b_id + b_idx + buf) + self.split
        while len(tosend) > 0:
            sent = self.send(tosend)
            tosend = tosend[sent:]
        self.ctl.server_send_buf_pool[self.i][cli_id].append((buf, b_idx))
        return len(buf)

    def id_write(self, cli_id, lastcontents=None, seq=None):
        # Write to a certain cli_id. Lastcontents is used for CLOSECHAR
        sent = 0
        try:
            if lastcontents is not None and seq is not None:
                sent += self.encrypt_and_send(cli_id,
                                              lastcontents,
                                              bytes(seq, 'utf-8'))
            sent = self.encrypt_and_send(cli_id)
            logging.debug('%04i to server' % sent)

        except KeyError:
            pass

    def update_max_idx(self, cli_id, seq):
        try:
            queue = self.ctl.server_send_buf_pool[self.i][cli_id]
            while len(queue) and queue[0][0] <= seq:
                queue.popleft()
        except Exception:
            pass
Пример #8
0
    def begin_auth(self):
        # Deal with the beginning authentication
        try:

            self.read += self.recv(2048)
            print("CALL AUTH")
            if b'\r\n' in self.read:
                authdata = self.read.split(b'\r\n')
                #print (authdata)
                # print(self.ctl.main_pw)
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    signer = PKCS1_v1_5.new(self.ctl.serverpub)
                    h = SHA256.new(self.ctl.main_pw)
                    verify = signer.verify(h, signature)
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning(
                        "Authentication failed, socket closing, case 1")
                    self.close()
                else:
                    try:
                        auth_cipher = PKCS_Cipher.new(self.ctl.clientpri)
                        sentinel = Random.new().read(32)
                        message = auth_cipher.decrypt(authdata[1], sentinel)
                        if len(message) != 16:
                            raise ValueError
                        self.cipher = AESCipher(
                            message, self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(b"2AUTHENTICATED" + authdata[2]  # +
                                                # repr(
                                                # self.ctl.server_recv_max_idx[self.i]).encode()
                                                )
                            #+ self.split
                        )
                        # self.send_legacy(
                        #    eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except IOError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing, , case 2")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()
Пример #9
0
class ServerReceiver_GAE(ServerReceiver):

    '''represent each connection with arkc-server'''

    def __init__(self, conn, ctl):
        ServerReceiver.__init__(self, conn, ctl)
        self.split = bytes(
            chr(27) +
            chr(28) +
            chr(27) +
            chr(28) +
            #"%X" % struct.unpack('B', self.ctl.main_pw[-2:-1])[0] +
            #"%X" % struct.unpack('B', self.ctl.main_pw[-3:-2])[0] +
            chr(31),
            "UTF-8"
        )

    def handle_read(self):
        """Handle received data."""

        b_close = bytes(CLOSECHAR, "ASCII")

        if self.cipher is None:
            self.begin_auth()
        else:
            read_count = 0
            self.from_remote_buffer_raw += self.recv(8192)
            # print(self.from_remote_buffer_raw)
            bytessplit = self.from_remote_buffer_raw.split(self.split)
            #print("CALL READ %d" % len(bytessplit))
            #print("PASSWORD IS " + repr(self.cipher.password))
            for Index in range(len(bytessplit)):

                if Index < len(bytessplit) - 1:
                    try:
                        b_dec = self.cipher.decrypt(bytessplit[Index])
                    except ValueError:
                        raw = bytessplit[Index]
                        print(raw)
                        print(len(raw))
                        raise
                    if len(b_dec) == 0:
                        continue
                    # flag is 0 for normal data packet, 1 for ping packet
                    flag = int(b_dec[:1].decode("UTF-8"))
                    if flag == 0:
                        try:
                            cli_id = b_dec[1:3].decode("UTF-8")
                            seq = int(b_dec[3:9].decode("UTF-8"))
                            b_data = b_dec[9:]
                        except Exception:
                            logging.warning("decode error")
                            cli_id = None
                        if cli_id == "00":
                            if b_data == b_close:

                                logging.debug("closing connection")
                                self.closing = True
                                self.ctl.closeconn(self)
                                self.close()
              #               elif seq == 50:
              #                   id_list = b_data.decode("UTF-8").split(',')
                            # self.ctl.server_check(id_list)
                            # TODO: Experimental function
                        else:
                            if cli_id in self.ctl.clientreceivers_dict:
                                if seq == 30:
                                    self.update_max_idx(cli_id,
                                                        int(b_data.decode('utf-8')))
                                elif b_data != b_close:
                                    self.ctl.server_recv_max_idx[
                                        self.i][cli_id] = seq
                                    self.ctl.clientreceivers_dict[
                                        cli_id].from_remote_buffer_dict[seq] = b_data
                                    # self.ctl.clientreceivers_dict[
                                    #    cli_id].retransmission_check()
                                else:
                                    for _ in self.ctl.server_recv_max_idx:
                                        if _ is not None:
                                            _.pop(cli_id, None)
                                    self.ctl.clientreceivers_dict[
                                        cli_id].close()
                                read_count += len(b_data)
                            # else:
                            #    self.encrypt_and_send(cli_id, CLOSECHAR)
                    else:
                        # strip off type (always 1)
                        self.ping_recv(b_dec[1:].decode("UTF-8"))

                else:
                    self.from_remote_buffer_raw = bytessplit[Index]
            if read_count > 0:
                logging.debug('%04i from server' % read_count)

    def begin_auth(self):
        # Deal with the beginning authentication
        try:

            self.read += self.recv(2048)
            print("CALL AUTH")
            if b'\r\n' in self.read:
                authdata = self.read.split(b'\r\n')
                #print (authdata)
                # print(self.ctl.main_pw)
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    signer = PKCS1_v1_5.new(self.ctl.serverpub)
                    h = SHA256.new(self.ctl.main_pw)
                    verify = signer.verify(h, signature)
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning(
                        "Authentication failed, socket closing, case 1")
                    self.close()
                else:
                    try:
                        auth_cipher = PKCS_Cipher.new(self.ctl.clientpri)
                        sentinel = Random.new().read(32)
                        message = auth_cipher.decrypt(authdata[1], sentinel)
                        if len(message) != 16:
                            raise ValueError
                        self.cipher = AESCipher(
                            message, self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(b"2AUTHENTICATED" + authdata[2]  # +
                                                # repr(
                                                # self.ctl.server_recv_max_idx[self.i]).encode()
                                                )
                            #+ self.split
                        )
                        # self.send_legacy(
                        #    eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except IOError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing, , case 2")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()

# WRITE PARTS NEED TO BE OPTIMIZED

    def writable(self):
        if self.preferred:
            for cli_id in self.ctl.clientreceivers_dict:
                if self.ctl.clientreceivers_dict[cli_id] is None:
                    logging.warning(
                        "Client receiver %s NoneType error" % cli_id)
                    del self.ctl.clientreceivers_dict[cli_id]
                else:
                    if SPLIT2 in self.ctl.clientreceivers_dict[cli_id].to_remote_buffer:
                        return True
            return False
        else:
            return False

    def handle_write(self):
        # Called when writable
        if self.cipher is not None:
            if self.ctl.ready == self:
                written = 0
                for cli_id in self.ctl.clientreceivers_dict:
                    if SPLIT2 in self.ctl.clientreceivers_dict[cli_id].to_remote_buffer:
                        self.id_write(cli_id)
                        written += 1
                    if written >= self.ctl.swapcount:
                        break
            self.ctl.refreshconn()
        else:
            self.handle_read()

    def encrypt_and_send(self, cli_id, buf=None, b_idx=None):
        """Encrypt and send data, and return the length sent.

        When `buf` is not specified, it is automatically read from the
        `to_remote_buffer` corresponding to `cli_id`.
        """
        b_id = bytes(cli_id, "UTF-8")
        if buf is None:
            b_idx = bytes(
                str(self.ctl.clientreceivers_dict[cli_id].to_remote_buffer_index), 'utf-8')
            splitted = self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer.split(SPLIT2)  # [SEG SIZE]
            if len(splitted) <= 1:
                return 0
            buf = splitted[0]
            print(repr(buf))
            self.ctl.clientreceivers_dict[cli_id].next_to_remote_buffer()
            self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer = b'\x00\x01\x02\x03\x04'.join(splitted[1:])
            if cli_id not in self.ctl.server_send_buf_pool[self.i]:
                self.ctl.server_send_buf_pool[self.i][cli_id] = []
        else:
            buf = bytes(buf, "utf-8")
        tosend = self.cipher.encrypt(
            b"0" + b_id + b_idx + buf) + self.split
        while len(tosend) > 0:
            sent = self.send(tosend)
            tosend = tosend[sent:]
        self.ctl.server_send_buf_pool[self.i][cli_id].append((buf, b_idx))
        return len(buf)

    def id_write(self, cli_id, lastcontents=None, seq=None):
        # Write to a certain cli_id. Lastcontents is used for CLOSECHAR
        sent = 0
        try:
            if lastcontents is not None and seq is not None:
                sent += self.encrypt_and_send(cli_id,
                                              lastcontents,
                                              bytes(seq, 'utf-8'))
            sent = self.encrypt_and_send(cli_id)
            logging.debug('%04i to server' % sent)

        except KeyError:
            pass

    def update_max_idx(self, cli_id, seq):
        try:
            queue = self.ctl.server_send_buf_pool[self.i][cli_id]
            while len(queue) and queue[0][0] <= seq:
                queue.popleft()
        except Exception:
            pass
Пример #10
0
class ServerReceiver(asyncore.dispatcher):
    '''represent each connection with arkc-server'''
    def __init__(self, conn, ctl):
        self.ctl = ctl
        asyncore.dispatcher.__init__(self, conn)
        self.read = b''
        self.from_remote_buffer_raw = b''
        self.cipher = None
        self.preferred = False
        self.closing = False
        self.i = -1
        self.split = bytes(
            chr(27) + chr(28) +
            "%X" % struct.unpack('B', self.ctl.main_pw[-2:-1])[0] +
            "%X" % struct.unpack('B', self.ctl.main_pw[-3:-2])[0] + chr(31),
            "UTF-8")
        self.no_data_count = 0
        self.read = b''
        self.latency = 10000
        time.sleep(0.05)  # async
        self.begin_auth()

    def ping_recv(self, msg):
        """Parse ping (without flag) and send back when necessary."""
        seq = int(msg[0])
        if seq == 0:
            raw_packet = "1" + "1" + msg[1:] + get_timestamp()
            to_write = self.cipher.encrypt(raw_packet) + self.split
            self.send(to_write)
        else:
            time1 = parse_timestamp(msg[1:])
            self.latency = int(time.time() * 1000) - time1
            logging.debug("latency: %dms" % self.latency)

    def handle_connect(self):
        pass

    def handle_read(self):
        """Handle received data."""

        b_close = bytes(CLOSECHAR, "ASCII")

        if self.cipher is None:
            self.begin_auth()
        else:
            read_count = 0
            self.from_remote_buffer_raw += self.recv(8192)
            bytessplit = self.from_remote_buffer_raw.split(self.split)
            for Index in range(len(bytessplit)):
                if Index < len(bytessplit) - 1:
                    b_dec = self.cipher.decrypt(bytessplit[Index])
                    # flag is 0 for normal data packet, 1 for ping packet
                    flag = int(b_dec[:1].decode("UTF-8"))
                    if flag == 0:
                        try:
                            cli_id = b_dec[1:3].decode("UTF-8")
                            seq = int(b_dec[3:9].decode("UTF-8"))
                            b_data = b_dec[9:]
                        except Exception:
                            logging.warning("decode error")
                            cli_id = None
                        if cli_id == "00":
                            if b_data == b_close:

                                logging.debug("closing connection")
                                self.closing = True
                                self.ctl.closeconn(self)
                                self.close()
            #               elif seq == 50:
            #                   id_list = b_data.decode("UTF-8").split(',')
            # self.ctl.server_check(id_list)
            # TODO: Experimental function
                        else:
                            if cli_id in self.ctl.clientreceivers_dict:
                                if seq == 30:
                                    self.update_max_idx(
                                        cli_id, int(b_data.decode('utf-8')))
                                elif b_data != b_close:
                                    self.ctl.server_recv_max_idx[
                                        self.i][cli_id] = seq
                                    self.ctl.clientreceivers_dict[
                                        cli_id].from_remote_buffer_dict[
                                            seq] = b_data
                                    self.ctl.clientreceivers_dict[
                                        cli_id].retransmission_check()
                                else:
                                    for _ in self.ctl.server_recv_max_idx:
                                        if _ is not None:
                                            _.pop(cli_id, None)
                                    self.ctl.clientreceivers_dict[
                                        cli_id].close()
                                read_count += len(b_data)
                            # else:
                            #    self.encrypt_and_send(cli_id, CLOSECHAR)
                    else:
                        # strip off type (always 1)
                        self.ping_recv(b_dec[1:].decode("UTF-8"))

                else:
                    self.from_remote_buffer_raw = bytessplit[Index]
            if read_count > 0:
                logging.debug('%04i from server' % read_count)

    def begin_auth(self):
        # Deal with the beginning authentication
        try:
            self.read += self.recv(2048)
            if self.split in self.read:
                authdata = self.read.split(b'\r\n')
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    verify = self.ctl.serverpub.verify(
                        self.ctl.main_pw, (int(signature, 36), None))
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning("Authentication failed, socket closing")
                    self.close()
                else:
                    try:
                        self.cipher = AESCipher(
                            self.ctl.clientpri.decrypt(authdata[1]),
                            self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(
                                b"2AUTHENTICATED" + authdata[2] +
                                repr(self.ctl.server_recv_max_idx[
                                    self.i]).encode()) + self.split)
                        self.send_legacy(
                            eval(authdata[3].rstrip(
                                self.split).decode('utf-8')))
                        self.read = None
                    except ValueError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()

    def send_legacy(self, idx_list):
        buf = self.ctl.server_send_buf_pool[self.i]
        for cli_id in idx_list:
            try:
                queue = buf[cli_id]
                while len(queue) and queue[0][0] <= idx_list[cli_id]:
                    queue.popleft()
                if len(queue):
                    for idx, data in queue:
                        self.encrypt_and_send(cli_id, data, idx)
            except Exception:
                pass

    def writable(self):
        if self.preferred:
            for cli_id in self.ctl.clientreceivers_dict:
                if self.ctl.clientreceivers_dict[cli_id] is None:
                    logging.warning("Client receiver %s NoneType error" %
                                    cli_id)
                    del self.ctl.clientreceivers_dict[cli_id]
                else:
                    if len(self.ctl.clientreceivers_dict[cli_id].
                           to_remote_buffer) > 0:
                        return True
        else:
            return False

    def handle_write(self):
        # Called when writable
        if self.cipher is not None:
            if self.ctl.ready == self:
                written = 0
                for cli_id in self.ctl.clientreceivers_dict:
                    if self.ctl.clientreceivers_dict[cli_id].to_remote_buffer:
                        self.id_write(cli_id)
                        written += 1
                    if written >= self.ctl.swapcount:
                        break
            self.ctl.refreshconn()
        else:
            self.handle_read()

    def handle_close(self):
        self.closing = True
        self.ctl.closeconn(self)
        self.close()

    def encrypt_and_send(self, cli_id, buf=None, b_idx=None):
        """Encrypt and send data, and return the length sent.

        When `buf` is not specified, it is automatically read from the
        `to_remote_buffer` corresponding to `cli_id`.
        """
        b_id = bytes(cli_id, "UTF-8")
        if buf is None:
            b_idx = bytes(
                str(self.ctl.clientreceivers_dict[cli_id].
                    to_remote_buffer_index), 'utf-8')
            buf = self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer[:SEG_SIZE]
            self.ctl.clientreceivers_dict[cli_id].next_to_remote_buffer()
            self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer = self.ctl.clientreceivers_dict[
                    cli_id].to_remote_buffer[len(buf):]
            if cli_id not in self.ctl.server_send_buf_pool[self.i]:
                self.ctl.server_send_buf_pool[self.i][cli_id] = []
        else:
            buf = bytes(buf, "utf-8")
        tosend = self.cipher.encrypt(b"0" + b_id + b_idx + buf) + self.split
        while len(tosend) > 0:
            sent = self.send(tosend)
            tosend = tosend[sent:]
        self.ctl.server_send_buf_pool[self.i][cli_id].append((buf, b_idx))
        return len(buf)

    def id_write(self, cli_id, lastcontents=None, seq=None):
        # Write to a certain cli_id. Lastcontents is used for CLOSECHAR
        sent = 0
        try:
            if lastcontents is not None and seq is not None:
                sent += self.encrypt_and_send(cli_id, lastcontents,
                                              bytes(seq, 'utf-8'))
            sent = self.encrypt_and_send(cli_id)
            logging.debug('%04i to server' % sent)

        except KeyError:
            pass

    def update_max_idx(self, cli_id, seq):
        try:
            queue = self.ctl.server_send_buf_pool[self.i][cli_id]
            while len(queue) and queue[0][0] <= seq:
                queue.popleft()
        except Exception:
            pass
Пример #11
0
    def begin_auth(self):
        # Deal with the beginning authentication
        try:

            self.read += self.recv(2048)
            print("CALL AUTH")
            if b'\r\n' in self.read:
                authdata = self.read.split(b'\r\n')
                #print (authdata)
                # print(self.ctl.main_pw)
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    signer = PKCS1_v1_5.new(self.ctl.serverpub)
                    h = SHA256.new(self.ctl.main_pw)
                    verify = signer.verify(h, signature)
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning(
                        "Authentication failed, socket closing, case 1")
                    self.close()
                else:
                    try:
                        auth_cipher = PKCS_Cipher.new(self.ctl.clientpri)
                        sentinel = Random.new().read(32)
                        message = auth_cipher.decrypt(authdata[1], sentinel)
                        if len(message) != 16:
                            raise ValueError
                        self.cipher = AESCipher(message, self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(
                                b"2AUTHENTICATED" + authdata[2]  # +
                                # repr(
                                # self.ctl.server_recv_max_idx[self.i]).encode()
                            )
                            #+ self.split
                        )
                        # self.send_legacy(
                        #    eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except IOError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing, , case 2")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()
Пример #12
0
class ServerReceiver_GAE(ServerReceiver):
    '''represent each connection with arkc-server'''
    def __init__(self, conn, ctl):
        ServerReceiver.__init__(self, conn, ctl)
        self.split = bytes(
            chr(27) + chr(28) + chr(27) + chr(28) +
            #"%X" % struct.unpack('B', self.ctl.main_pw[-2:-1])[0] +
            #"%X" % struct.unpack('B', self.ctl.main_pw[-3:-2])[0] +
            chr(31),
            "UTF-8")

    def handle_read(self):
        """Handle received data."""

        b_close = bytes(CLOSECHAR, "ASCII")

        if self.cipher is None:
            self.begin_auth()
        else:
            read_count = 0
            self.from_remote_buffer_raw += self.recv(8192)
            # print(self.from_remote_buffer_raw)
            bytessplit = self.from_remote_buffer_raw.split(self.split)
            #print("CALL READ %d" % len(bytessplit))
            #print("PASSWORD IS " + repr(self.cipher.password))
            for Index in range(len(bytessplit)):

                if Index < len(bytessplit) - 1:
                    try:
                        b_dec = self.cipher.decrypt(bytessplit[Index])
                    except ValueError:
                        raw = bytessplit[Index]
                        print(raw)
                        print(len(raw))
                        raise
                    if len(b_dec) == 0:
                        continue
                    # flag is 0 for normal data packet, 1 for ping packet
                    flag = int(b_dec[:1].decode("UTF-8"))
                    if flag == 0:
                        try:
                            cli_id = b_dec[1:3].decode("UTF-8")
                            seq = int(b_dec[3:9].decode("UTF-8"))
                            b_data = b_dec[9:]
                        except Exception:
                            logging.warning("decode error")
                            cli_id = None
                        if cli_id == "00":
                            if b_data == b_close:

                                logging.debug("closing connection")
                                self.closing = True
                                self.ctl.closeconn(self)
                                self.close()
            #               elif seq == 50:
            #                   id_list = b_data.decode("UTF-8").split(',')
            # self.ctl.server_check(id_list)
            # TODO: Experimental function
                        else:
                            if cli_id in self.ctl.clientreceivers_dict:
                                if seq == 30:
                                    self.update_max_idx(
                                        cli_id, int(b_data.decode('utf-8')))
                                elif b_data != b_close:
                                    self.ctl.server_recv_max_idx[
                                        self.i][cli_id] = seq
                                    self.ctl.clientreceivers_dict[
                                        cli_id].from_remote_buffer_dict[
                                            seq] = b_data
                                    # self.ctl.clientreceivers_dict[
                                    #    cli_id].retransmission_check()
                                else:
                                    for _ in self.ctl.server_recv_max_idx:
                                        if _ is not None:
                                            _.pop(cli_id, None)
                                    self.ctl.clientreceivers_dict[
                                        cli_id].close()
                                read_count += len(b_data)
                            # else:
                            #    self.encrypt_and_send(cli_id, CLOSECHAR)
                    else:
                        # strip off type (always 1)
                        self.ping_recv(b_dec[1:].decode("UTF-8"))

                else:
                    self.from_remote_buffer_raw = bytessplit[Index]
            if read_count > 0:
                logging.debug('%04i from server' % read_count)

    def begin_auth(self):
        # Deal with the beginning authentication
        try:

            self.read += self.recv(2048)
            print("CALL AUTH")
            if b'\r\n' in self.read:
                authdata = self.read.split(b'\r\n')
                #print (authdata)
                # print(self.ctl.main_pw)
                signature = authdata[0]
                # TODO: fix an error in int(signature,16)
                try:
                    signer = PKCS1_v1_5.new(self.ctl.serverpub)
                    h = SHA256.new(self.ctl.main_pw)
                    verify = signer.verify(h, signature)
                except ValueError:
                    logging.debug("ValueError captured at server.py line 165")
                    verify = False
                if not verify:
                    logging.warning(
                        "Authentication failed, socket closing, case 1")
                    self.close()
                else:
                    try:
                        auth_cipher = PKCS_Cipher.new(self.ctl.clientpri)
                        sentinel = Random.new().read(32)
                        message = auth_cipher.decrypt(authdata[1], sentinel)
                        if len(message) != 16:
                            raise ValueError
                        self.cipher = AESCipher(message, self.ctl.main_pw)
                        self.full = False
                        idchar = authdata[2].decode('utf-8')
                        self.i = int(idchar)
                        self.ctl.newconn(self)
                        logging.debug(
                            "Authentication succeed, connection established")
                        self.send(
                            self.cipher.encrypt(
                                b"2AUTHENTICATED" + authdata[2]  # +
                                # repr(
                                # self.ctl.server_recv_max_idx[self.i]).encode()
                            )
                            #+ self.split
                        )
                        # self.send_legacy(
                        #    eval(authdata[3].rstrip(self.split).decode('utf-8')))
                        self.read = None
                    except IOError:
                        # TODO: figure out why
                        logging.warning(
                            "Authentication failed, socket closing, , case 2")
                        self.handle_close()
            else:
                if len(self.read) == 0:
                    self.no_data_count += 1
        except BlockingIOError:
            pass

        except socket.error:
            logging.info("empty recv error")

        except Exception as err:
            raise err
            logging.error(
                "Authentication failed, due to error, socket closing")
            self.close()

# WRITE PARTS NEED TO BE OPTIMIZED

    def writable(self):
        if self.preferred:
            for cli_id in self.ctl.clientreceivers_dict:
                if self.ctl.clientreceivers_dict[cli_id] is None:
                    logging.warning("Client receiver %s NoneType error" %
                                    cli_id)
                    del self.ctl.clientreceivers_dict[cli_id]
                else:
                    if SPLIT2 in self.ctl.clientreceivers_dict[
                            cli_id].to_remote_buffer:
                        return True
            return False
        else:
            return False

    def handle_write(self):
        # Called when writable
        if self.cipher is not None:
            if self.ctl.ready == self:
                written = 0
                for cli_id in self.ctl.clientreceivers_dict:
                    if SPLIT2 in self.ctl.clientreceivers_dict[
                            cli_id].to_remote_buffer:
                        self.id_write(cli_id)
                        written += 1
                    if written >= self.ctl.swapcount:
                        break
            self.ctl.refreshconn()
        else:
            self.handle_read()

    def encrypt_and_send(self, cli_id, buf=None, b_idx=None):
        """Encrypt and send data, and return the length sent.

        When `buf` is not specified, it is automatically read from the
        `to_remote_buffer` corresponding to `cli_id`.
        """
        b_id = bytes(cli_id, "UTF-8")
        if buf is None:
            b_idx = bytes(
                str(self.ctl.clientreceivers_dict[cli_id].
                    to_remote_buffer_index), 'utf-8')
            splitted = self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer.split(SPLIT2)  # [SEG SIZE]
            if len(splitted) <= 1:
                return 0
            buf = splitted[0]
            print(repr(buf))
            self.ctl.clientreceivers_dict[cli_id].next_to_remote_buffer()
            self.ctl.clientreceivers_dict[
                cli_id].to_remote_buffer = b'\x00\x01\x02\x03\x04'.join(
                    splitted[1:])
            if cli_id not in self.ctl.server_send_buf_pool[self.i]:
                self.ctl.server_send_buf_pool[self.i][cli_id] = []
        else:
            buf = bytes(buf, "utf-8")
        tosend = self.cipher.encrypt(b"0" + b_id + b_idx + buf) + self.split
        while len(tosend) > 0:
            sent = self.send(tosend)
            tosend = tosend[sent:]
        self.ctl.server_send_buf_pool[self.i][cli_id].append((buf, b_idx))
        return len(buf)

    def id_write(self, cli_id, lastcontents=None, seq=None):
        # Write to a certain cli_id. Lastcontents is used for CLOSECHAR
        sent = 0
        try:
            if lastcontents is not None and seq is not None:
                sent += self.encrypt_and_send(cli_id, lastcontents,
                                              bytes(seq, 'utf-8'))
            sent = self.encrypt_and_send(cli_id)
            logging.debug('%04i to server' % sent)

        except KeyError:
            pass

    def update_max_idx(self, cli_id, seq):
        try:
            queue = self.ctl.server_send_buf_pool[self.i][cli_id]
            while len(queue) and queue[0][0] <= seq:
                queue.popleft()
        except Exception:
            pass