Esempio n. 1
0
    def sendall(self, data):
        data_more = None
        if self.connected == 0:
            logger.debug('hxsocks send connect request')
            self.cipher = encrypt.AEncryptor(keys[self.serverid][1],
                                             self.method, salt, ctx, 0)

            pt = struct.pack('>I', int(time.time())) + chr(len(
                self._address)) + self._address + data
            if len(pt) > 65500:
                pt, data_more = pt[:65500], pt[65500]
            ct, mac = self.cipher.encrypt(pt)
            self._sock.sendall(
                self.pskcipher.encrypt(
                    chr(11) + keys[self.serverid][0] +
                    struct.pack('>H', len(ct))) + ct + mac)
            if data and self._data_bak is None:
                self._data_bak = data
            self.connected = 1
        else:
            if len(data) > 65500:
                data, data_more = data[:65500], data[65500]

            padding_len = random.randint(64, 255) if len(data) < 256 else 0
            padding = (b'\x00' * padding_len) if padding_len else b''
            data = chr(padding_len) + data + padding

            ct, mac = self.cipher.encrypt(data)
            data = self.pskcipher.encrypt(struct.pack('>H',
                                                      len(ct))) + ct + mac
            self._sock.sendall(data)
        if data_more:
            self.sendall(data_more)
Esempio n. 2
0
    def handle(self):
        try:
            self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
                                       1)
            pskcipher = encrypt.Encryptor(self.server.PSK, self.server.method)
            self.connection.settimeout(self.timeout)
            data = self.rfile.read(pskcipher.iv_len)
            pskcipher.decrypt(data)
            while True:
                try:
                    data = self.rfile.read(1)
                    self.connection.settimeout(self.timeout)
                    cmd = ord(pskcipher.decrypt(data))
                except Exception as e:
                    logging.error(
                        'cmd Exception: server %s %r from %s:%s' %
                        (self.server.server_address[1], e,
                         self.client_address[0], self.client_address[1]))
                    break
                if cmd == 10:  # client key exchange
                    rint = random.randint(64, 255)
                    req_len = pskcipher.decrypt(self.rfile.read(2))
                    req_len = struct.unpack('>H', req_len)[0]
                    data = pskcipher.decrypt(self.rfile.read(req_len))
                    data = io.BytesIO(data)
                    ts = data.read(4)
                    if abs(struct.unpack('>I', ts)[0] - time.time()) > 120:
                        # possible replay attack
                        logging.error('bad timestamp. client_ip: %s' %
                                      self.client_address[0])
                        break
                    pklen = ord(data.read(1))
                    client_pkey = data.read(pklen)
                    client_auth = data.read(32)

                    def _send(data):
                        data = struct.pack('>H', len(data)) + data
                        self.wfile.write(pskcipher.encrypt(data))

                    client = None
                    for user, passwd in USER_PASS.items():
                        h = hmac.new(passwd.encode(),
                                     ts + client_pkey + user.encode(),
                                     hashlib.sha256).digest()
                        if compare_digest(h, client_auth):
                            client = user
                            break
                    else:
                        logging.error('user not found. client_ip: %s' %
                                      self.client_address[0])
                        break
                    pkey, passwd = KeyManager.create_key(
                        client, client_pkey, pskcipher.key_len)
                    if pkey:
                        logging.info('new key exchange. client: %s, ip: %s' %
                                     (client, self.client_address[0]))
                        h = hmac.new(passwd.encode(),
                                     client_pkey + pkey + client.encode(),
                                     hashlib.sha256).digest()
                        scert = SERVER_CERT.get_pub_key()
                        signature = SERVER_CERT.sign(h, self.server.hash_algo)
                        data = chr(0) + chr(len(pkey)) + chr(len(scert)) + chr(
                            len(signature)
                        ) + pkey + h + scert + signature + os.urandom(rint)
                        _send(data)
                        continue
                    else:
                        logging.error(
                            'Private_key already registered. client: %s, ip: %s'
                            % (client, self.client_address[0]))
                        # KeyManager.del_key(hashlib.md5(client_pkey).digest())
                        break
                elif cmd == 11:  # a connect request
                    client_pkey = pskcipher.decrypt(self.rfile.read(16))
                    rint = random.randint(64, 2048)

                    def _send(code, cipher):
                        if code == 1:
                            data = os.urandom(rint)
                            data = pskcipher.encrypt(struct.pack('>H',
                                                                 rint)) + data
                            self.wfile.write(data)
                        else:
                            ct = cipher.encrypt(
                                chr(code) + os.urandom(rint - 1))
                            data = pskcipher.encrypt(struct.pack(
                                '>H', len(ct))) + ct
                            self.wfile.write(data)

                    if KeyManager.check_key(client_pkey):
                        logging.error(
                            'client key not exist or expired. client ip: %s' %
                            self.client_address[0])
                        ctlen = struct.unpack(
                            '>H', pskcipher.decrypt(self.rfile.read(2)))[0]
                        self.rfile.read(ctlen)
                        _send(1, None)
                        continue

                    user = KeyManager.get_user_by_pubkey(client_pkey)
                    cipher = encrypt.AEncryptor(
                        KeyManager.get_skey_by_pubkey(client_pkey),
                        self.server.method, CTX)
                    ctlen = struct.unpack(
                        '>H', pskcipher.decrypt(self.rfile.read(2)))[0]
                    ct = self.rfile.read(ctlen)
                    data = cipher.decrypt(ct)
                    buf = io.BytesIO(data)
                    ts = buf.read(4)
                    if abs(struct.unpack('>I', ts)[0] - time.time()) > 120:
                        logging.error(
                            'bad timestamp, possible replay attrack. client ip: %s'
                            % self.client_address[0])
                        # KeyManager.del_key(client_pkey)
                        # _send(1, None)
                        break
                    host_len = ord(buf.read(1))
                    addr = buf.read(host_len)
                    port = struct.unpack('>H', buf.read(2))[0]
                    if self._request_is_loopback(
                        (addr, port)) and port not in self.server.forward:
                        logging.info(
                            'server %d access localhost:%d denied. from %s:%d, %s'
                            % (self.server.server_address[1], port,
                               self.client_address[0], self.client_address[1],
                               user))
                        _send(2, cipher)
                        continue
                    try:
                        logging.info('server %d request %s:%d from %s:%d, %s' %
                                     (self.server.server_address[1], addr,
                                      port, self.client_address[0],
                                      self.client_address[1], user))
                        remote = create_connection((addr, port),
                                                   timeout=10,
                                                   proxy=self.server.proxy)
                        remote.setsockopt(socket.IPPROTO_TCP,
                                          socket.TCP_NODELAY, 1)
                        _send(0, cipher)
                        # self.remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    except (IOError, OSError) as e:  # Connection refused
                        logging.warning(
                            'server %s:%d %r on connecting %s:%d' %
                            (self.server.server_address[0],
                             self.server.server_address[1], e, addr, port))
                        _send(2, cipher)
                        continue
                    if self.forward_tcp(self.connection,
                                        remote,
                                        cipher,
                                        pskcipher,
                                        timeout=60):
                        break
                    self.connection.settimeout(60)
                    logging.debug(
                        'hxsocks connect reusable, except next connection')
                elif cmd in (1, 3, 4, 17, 19, 20):
                    # A shadowsocks request
                    if not self.server.ss:
                        logging.warning(
                            'shadowsocks not enabled for this server. port: %d'
                            % self.server.server_address[1])
                        break
                    ota = cmd & 16
                    if cmd & 15 == 1:
                        _addr = pskcipher.decrypt(self.rfile.read(4))
                        addr = socket.inet_ntoa(_addr)
                    elif cmd & 15 == 3:
                        _addr = pskcipher.decrypt(self.rfile.read(1))
                        addr = pskcipher.decrypt(self.rfile.read(ord(_addr)))
                        _addr += addr
                    elif cmd & 15 == 4:
                        _addr = socket.AF_INET6, pskcipher.decrypt(
                            self.rfile.read(16))
                        addr = socket.inet_ntop(_addr)
                    port = struct.unpack('>H',
                                         pskcipher.decrypt(
                                             self.rfile.read(2)))[0]
                    # verify
                    if ota:
                        header = chr(cmd) + _addr + struct.pack('>H', port)
                        self._ota_chunk_idx = 0
                        rmac = pskcipher.decrypt(self.rfile.read(10))
                        key = pskcipher.decipher_iv + pskcipher.key
                        mac = hmac.new(key, header, hashlib.sha1).digest()[:10]
                        if not compare_digest(rmac, mac):
                            logging.error("OTA Failed!!")
                            break

                    if self._request_is_loopback(
                        (addr, port)) and port not in self.server.forward:
                        logging.info(
                            'server %d access localhost:%d denied. from %s:%d'
                            % (self.server.server_address[1], port,
                               self.client_address[0], self.client_address[1]))
                        break
                    try:
                        remote = None
                        logging.info(
                            'server %d SS request %s:%d from %s:%d %s' %
                            (self.server.server_address[1], addr, port,
                             self.client_address[0], self.client_address[1],
                             'with ota' if ota else ''))
                        remote = create_connection((addr, port),
                                                   timeout=10,
                                                   proxy=self.server.proxy)
                        if ota:
                            return self.ssforward_tcp_ota(self.connection,
                                                          remote,
                                                          pskcipher,
                                                          timeout=60)
                        return self.ssforward_tcp(self.connection,
                                                  remote,
                                                  pskcipher,
                                                  timeout=60)
                    except (IOError, OSError) as e:  # Connection refused
                        logging.warn(
                            'server %s:%d %r on connecting %s:%d' %
                            (self.server.server_address[0],
                             self.server.server_address[1], e, addr, port))
                        return
                else:
                    logging.warning('unknown cmd %d, bad encryption key?' %
                                    cmd)
                    break
            ins, _, _ = select.select([self.connection], [], [], 1)
            while ins:
                data = self.connection.recv(self.bufsize)
                if not data:
                    break
                ins, _, _ = select.select([self.connection], [], [], 1)
        except Exception as e:
            logging.error(repr(e))
            logging.error(traceback.format_exc())
Esempio n. 3
0
    def getKey(self):
        with newkey_lock[self.serverid]:
            if self.serverid not in keys:
                for _ in range(2):
                    logger.debug('hxsocks getKey')
                    host, port, usn, psw = (self.hxsServer.hostname,
                                            self.hxsServer.port,
                                            self.hxsServer.username,
                                            self.hxsServer.password)
                    if self._sock is None:
                        logger.debug('hxsocks connect')
                        from connection import create_connection
                        self._sock = create_connection(
                            (host, port),
                            self.timeout,
                            parentproxy=self.parentproxy,
                            tunnel=True)
                        self.pskcipher = encrypt.Encryptor(
                            self.PSK, self.method)
                        self._rfile = self._sock.makefile('rb')
                        self._header_sent = False
                        self._header_received = False
                    acipher = ECC(self.pskcipher.key_len)
                    pubk = acipher.get_pub_key()
                    logger.debug('hxsocks send key exchange request')
                    ts = struct.pack('>I', int(time.time()))
                    padding_len = random.randint(64, 255)
                    data = b''.join([
                        ts,
                        chr(len(pubk)).encode('latin1'), pubk,
                        hmac.new(psw.encode(), ts + pubk + usn.encode(),
                                 hashlib.sha256).digest(),
                        b'\x00' * padding_len
                    ])
                    data = chr(10).encode() + struct.pack('>H',
                                                          len(data)) + data
                    self._sock_sendall(self.pskcipher.encrypt(data))
                    resp_len = 2 if self.pskcipher.decipher else self.pskcipher.iv_len + 2
                    resp_len = self.pskcipher.decrypt(
                        self._rfile_read(resp_len))
                    resp_len = struct.unpack('>H', resp_len)[0]
                    data = self.pskcipher.decrypt(self._rfile_read(resp_len))

                    data = io.BytesIO(data)

                    resp_code = byte2int(data.read(1))
                    if resp_code == 0:
                        logger.debug('hxsocks read key exchange respond')
                        pklen = byte2int(data.read(1))
                        scertlen = byte2int(data.read(1))
                        siglen = byte2int(data.read(1))

                        server_key = data.read(pklen)
                        auth = data.read(32)
                        server_cert = data.read(scertlen)
                        signature = data.read(siglen)

                        # TODO: ask user if a certificate should be accepted or not.
                        if host not in known_hosts:
                            logger.info(
                                'hxs: server %s new cert %s saved.' %
                                (host,
                                 hashlib.sha256(server_cert).hexdigest()[:8]))
                            with open('./.hxs_known_hosts/' + host + '.cert',
                                      'wb') as f:
                                f.write(server_cert)
                                known_hosts[host] = server_cert
                        elif known_hosts[host] != server_cert:
                            logger.error(
                                'hxs: server %s certificate mismatch! PLEASE CHECK!'
                                % host)
                            raise OSError(0, 'hxs: bad certificate')
                        if auth == hmac.new(psw.encode(),
                                            pubk + server_key + usn.encode(),
                                            hashlib.sha256).digest():
                            if ECC.verify_with_pub_key(server_cert, auth,
                                                       signature,
                                                       self.hash_algo):
                                shared_secret = acipher.get_dh_key(server_key)
                                keys[self.serverid] = (
                                    hashlib.md5(pubk).digest(), shared_secret)
                                self.cipher = encrypt.AEncryptor(
                                    keys[self.serverid][1], self.method, SALT,
                                    CTX, 0, MAC_LEN)
                                logger.debug('hxs key exchange success')
                                return
                            else:
                                logger.error(
                                    'hxs getKey Error: server auth failed, bad signature'
                                )
                        else:
                            logger.error(
                                'hxs getKey Error: server auth failed, bad username or password'
                            )
                    else:
                        logger.error(
                            'hxs getKey Error. bad password or timestamp.')
                else:
                    raise IOError(0, 'hxs getKey Error')
            else:
                self.cipher = encrypt.AEncryptor(keys[self.serverid][1],
                                                 self.method, SALT, CTX, 0,
                                                 MAC_LEN)