def load_openssl(): global loaded, libcrypto, buf from ctypes.util import find_library for p in ('crypto', 'eay32', 'libeay32'): libcrypto_path = find_library(p) if libcrypto_path: break else: raise Exception('libcrypto(OpenSSL) not found') logging.info('loading libcrypto from %s', libcrypto_path) libcrypto = CDLL(libcrypto_path) libcrypto.EVP_get_cipherbyname.restype = c_void_p libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p libcrypto.EVP_CipherInit_ex.argtypes = (c_void_p, c_void_p, c_char_p, c_char_p, c_char_p, c_int) libcrypto.EVP_CipherUpdate.argtypes = (c_void_p, c_void_p, c_void_p, c_char_p, c_int) libcrypto.EVP_CIPHER_CTX_cleanup.argtypes = (c_void_p,) libcrypto.EVP_CIPHER_CTX_free.argtypes = (c_void_p,) if hasattr(libcrypto, 'OpenSSL_add_all_ciphers'): libcrypto.OpenSSL_add_all_ciphers() buf = create_string_buffer(buf_size) loaded = True
def client_decode(self, buf): if self.handshake_status == -1: return (buf, False) if self.handshake_status == 8: ret = b'' self.recv_buffer += buf while len(self.recv_buffer) > 5: if ord(self.recv_buffer[0]) != 0x17: logging.info("data = %s" % (binascii.hexlify(self.recv_buffer))) raise Exception('server_decode appdata error') size = struct.unpack('>H', self.recv_buffer[3:5])[0] if len(self.recv_buffer) < size + 5: break buf = self.recv_buffer[5:size + 5] ret += buf self.recv_buffer = self.recv_buffer[size + 5:] return (ret, False) if len(buf) < 11 + 32 + 1 + 32: raise Exception('client_decode data error') verify = buf[11:33] if hmac.new(self.server_info.key + self.server_info.data.client_id, verify, hashlib.sha1).digest()[:10] != buf[33:43]: raise Exception('client_decode data error') if hmac.new(self.server_info.key + self.server_info.data.client_id, buf[:-10], hashlib.sha1).digest()[:10] != buf[-10:]: raise Exception('client_decode data error') return (b'', True)
def load_libsodium(): global loaded, libsodium, buf from ctypes.util import find_library for p in ('sodium',): libsodium_path = find_library(p) if libsodium_path: break else: raise Exception('libsodium not found') logging.info('loading libsodium from %s', libsodium_path) libsodium = CDLL(libsodium_path) libsodium.sodium_init.restype = c_int libsodium.crypto_stream_salsa20_xor_ic.restype = c_int libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) libsodium.crypto_stream_chacha20_xor_ic.restype = c_int libsodium.crypto_stream_chacha20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) libsodium.sodium_init() buf = create_string_buffer(buf_size) loaded = True
def find_library(possible_lib_names, search_symbol, library_name): import ctypes.util from ctypes import CDLL paths = [] if type(possible_lib_names) not in (list, tuple): possible_lib_names = [possible_lib_names] lib_names = [] for lib_name in possible_lib_names: lib_names.append(lib_name) lib_names.append('lib' + lib_name) for name in lib_names: if os.name == "nt": paths.extend(find_library_nt(name)) else: path = ctypes.util.find_library(name) if path: paths.append(path) # always find lib on extend path that to avoid ```CDLL()``` failed on some strange linux environment # in that case ```ctypes.util.find_library()``` have different find path from ```CDLL()``` if True: # We may get here when find_library fails because, for example, # the user does not have sufficient privileges to access those # tools underlying find_library on linux. import glob for name in lib_names: patterns = [ '/usr/local/lib*/lib%s.*' % name, '/usr/lib*/lib%s.*' % name, 'lib%s.*' % name, '%s.dll' % name ] for pat in patterns: files = glob.glob(pat) if files: paths.extend(files) for path in paths: try: lib = CDLL(path) if hasattr(lib, search_symbol): logging.info('loading %s from %s', library_name, path) return lib else: logging.warn('can\'t find symbol %s in %s', search_symbol, path) except Exception: if path == paths[-1]: raise return None
def client_post_decrypt(self, buf): if self.raw_trans: return buf self.recv_buf += buf out_buf = b'' while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) data_len = struct.unpack('<H', self.recv_buf[:2])[0] ^ struct.unpack('<H', self.last_server_hash[14:16])[0] rand_len = self.rnd_data_len(data_len, self.last_server_hash, self.random_server) length = data_len + rand_len if length >= 4096: self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data error') if length + 4 > len(self.recv_buf): break server_hash = hmac.new(mac_key, self.recv_buf[:length + 2], self.hashfunc).digest() if server_hash[:2] != self.recv_buf[length + 2: length + 4]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data uncorrect checksum') pos = 2 if data_len > 0 and rand_len > 0: pos = 2 + self.rnd_start_pos(rand_len, self.random_server) out_buf += self.encryptor.decrypt(self.recv_buf[pos: data_len + pos]) self.last_server_hash = server_hash if self.recv_id == 1: self.server_info.tcp_mss = struct.unpack('<H', out_buf[:2])[0] out_buf = out_buf[2:] self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF self.recv_buf = self.recv_buf[length + 4:] return out_buf
def load_libsodium(): global loaded, libsodium, buf libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic', 'libsodium') if libsodium is None: raise Exception('libsodium not found') libsodium.crypto_stream_salsa20_xor_ic.restype = c_int libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) libsodium.crypto_stream_chacha20_xor_ic.restype = c_int libsodium.crypto_stream_chacha20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) try: libsodium.crypto_stream_chacha20_ietf_xor_ic.restype = c_int libsodium.crypto_stream_chacha20_ietf_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulong, c_char_p) except: logging.info("ChaCha20 IETF not support.") pass try: libsodium.crypto_stream_xsalsa20_xor_ic.restype = c_int libsodium.crypto_stream_xsalsa20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) except: logging.info("XSalsa20 not support.") pass try: libsodium.crypto_stream_xchacha20_xor_ic.restype = c_int libsodium.crypto_stream_xchacha20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, c_char_p, c_ulonglong, c_char_p) except: logging.info( "XChaCha20 not support. XChaCha20 only support since libsodium v1.0.12" ) pass buf = create_string_buffer(buf_size) loaded = True
def log_shadowsocks_version(): logging.info('ShadowsocksR %s' % __version())
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) >= 12 or len(self.recv_buf) in [7, 8]: recv_len = min(len(self.recv_buf), 12) mac_key = self.server_info.recv_iv + self.server_info.key md5data = hmac.new(mac_key, self.recv_buf[:4], self.hashfunc).digest() if md5data[:recv_len - 4] != self.recv_buf[4:recv_len]: return self.not_match_return(self.recv_buf) if len(self.recv_buf) < 12 + 24: return (b'', False) self.last_client_hash = md5data uid = struct.unpack('<I', self.recv_buf[12:16])[0] ^ struct.unpack('<I', md5data[8:12])[0] self.user_id_num = uid uid = struct.pack('<I', uid) if uid in self.server_info.users: self.user_id = uid self.user_key = self.server_info.users[uid] self.server_info.update_user_func(uid) else: self.user_id_num = 0 if not self.server_info.users: self.user_key = self.server_info.key else: self.user_key = self.server_info.recv_iv md5data = hmac.new(self.user_key, self.recv_buf[12: 12 + 20], self.hashfunc).digest() if md5data[:4] != self.recv_buf[32:36]: logging.error('%s data uncorrect auth HMAC-MD5 from %s:%d, data %s' % ( self.no_compatible_method, self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf) )) if len(self.recv_buf) < 36: return (b'', False) return self.not_match_return(self.recv_buf) self.last_server_hash = md5data encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc') head = encryptor.decrypt(b'\x00' * 16 + self.recv_buf[16:32] + b'\x00') # need an extra byte or recv empty self.client_over_head = struct.unpack('<H', head[12:14])[0] utc_time = struct.unpack('<I', head[:4])[0] client_id = struct.unpack('<I', head[4:8])[0] connection_id = struct.unpack('<I', head[8:12])[0] time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('%s: wrong timestamp, time_dif %d, data %s' % ( self.no_compatible_method, time_dif, binascii.hexlify(head) )) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(self.user_id, client_id, connection_id): self.has_recv_header = True self.client_id = client_id self.connection_id = connection_id else: logging.info('%s: auth fail, data %s' % (self.no_compatible_method, binascii.hexlify(out_buf))) return self.not_match_return(self.recv_buf) self.on_recv_auth_data(utc_time) self.encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + to_bytes(base64.b64encode(self.last_client_hash)), 'rc4') self.recv_buf = self.recv_buf[36:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) data_len = struct.unpack('<H', self.recv_buf[:2])[0] ^ struct.unpack('<H', self.last_client_hash[14:16])[0] rand_len = self.rnd_data_len(data_len, self.last_client_hash, self.random_client) length = data_len + rand_len if length >= 4096: self.raw_trans = True self.recv_buf = b'' if self.recv_id == 1: logging.info(self.no_compatible_method + ': over size') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') if length + 4 > len(self.recv_buf): break client_hash = hmac.new(mac_key, self.recv_buf[:length + 2], self.hashfunc).digest() if client_hash[:2] != self.recv_buf[length + 2: length + 4]: logging.info('%s: checksum error, data %s' % ( self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]) )) self.raw_trans = True self.recv_buf = b'' if self.recv_id == 1: return (b'E' * 2048, False) else: raise Exception('server_post_decrype data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = 2 if data_len > 0 and rand_len > 0: pos = 2 + self.rnd_start_pos(rand_len, self.random_client) out_buf += self.encryptor.decrypt(self.recv_buf[pos: data_len + pos]) self.last_client_hash = client_hash self.recv_buf = self.recv_buf[length + 4:] if data_len == 0: sendback = True if out_buf: self.server_info.data.update(self.user_id, self.client_id, self.connection_id) return (out_buf, sendback)
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) >= 7 or len(self.recv_buf) in [2, 3]: recv_len = min(len(self.recv_buf), 7) mac_key = self.server_info.recv_iv + self.server_info.key sha1data = hmac.new(mac_key, self.recv_buf[:1], self.hashfunc).digest()[:recv_len - 1] if sha1data != self.recv_buf[1:recv_len]: return self.not_match_return(self.recv_buf) if len(self.recv_buf) < 31: return (b'', False) sha1data = hmac.new(mac_key, self.recv_buf[7:27], self.hashfunc).digest()[:4] if sha1data != self.recv_buf[27:31]: logging.error('%s data uncorrect auth HMAC-SHA1 from %s:%d, data %s' % (self.no_compatible_method, self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf))) if len(self.recv_buf) < 31 + self.extra_wait_size: return (b'', False) return self.not_match_return(self.recv_buf) uid = self.recv_buf[7:11] if uid in self.server_info.users: self.user_id = uid self.user_key = self.hashfunc(self.server_info.users[uid]).digest() self.server_info.update_user_func(uid) else: if not self.server_info.users: self.user_key = self.server_info.key else: self.user_key = self.server_info.recv_iv encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc') head = encryptor.decrypt(b'\x00' * 16 + self.recv_buf[11:27] + b'\x00') # need an extra byte or recv empty length = struct.unpack('<H', head[12:14])[0] if len(self.recv_buf) < length: return (b'', False) utc_time = struct.unpack('<I', head[:4])[0] client_id = struct.unpack('<I', head[4:8])[0] connection_id = struct.unpack('<I', head[8:12])[0] rnd_len = struct.unpack('<H', head[14:16])[0] if hmac.new(self.user_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) return self.not_match_return(self.recv_buf) time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('%s: wrong timestamp, time_dif %d, data %s' % (self.no_compatible_method, time_dif, binascii.hexlify(head))) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(self.user_id, client_id, connection_id): self.has_recv_header = True out_buf = self.recv_buf[31 + rnd_len:length - 4] self.client_id = client_id self.connection_id = connection_id else: logging.info('%s: auth fail, data %s' % (self.no_compatible_method, binascii.hexlify(out_buf))) return self.not_match_return(self.recv_buf) self.recv_buf = self.recv_buf[length:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) mac = hmac.new(mac_key, self.recv_buf[:2], self.hashfunc).digest()[:2] if mac != self.recv_buf[2:4]: self.raw_trans = True logging.info(self.no_compatible_method + ': wrong crc') if self.recv_id == 0: logging.info(self.no_compatible_method + ': wrong crc') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') length = struct.unpack('<H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: logging.info(self.no_compatible_method + ': over size') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') if length > len(self.recv_buf): break if hmac.new(mac_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: return (b'E'*2048, False) else: raise Exception('server_post_decrype data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('<H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if pos == length - 4: sendback = True if out_buf: self.server_info.data.update(self.user_id, self.client_id, self.connection_id) return (out_buf, sendback)
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) <= 6: return (b'', False) crc = struct.pack('<I', binascii.crc32(self.recv_buf[:2] + self.salt + self.server_info.key) & 0xFFFFFFFF) if crc != self.recv_buf[2:6]: return self.not_match_return(self.recv_buf) length = struct.unpack('>H', self.recv_buf[:2])[0] if length > len(self.recv_buf): return (b'', False) sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, self.recv_buf[:length - 10], hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[length - 10:length]: logging.error('auth_sha1_v4 data uncorrect auth HMAC-SHA1') return self.not_match_return(self.recv_buf) pos = common.ord(self.recv_buf[6]) if pos < 255: pos += 6 else: pos = struct.unpack('>H', self.recv_buf[7:9])[0] + 6 out_buf = self.recv_buf[pos:length - 10] if len(out_buf) < 12: logging.info('auth_sha1_v4: too short, data %s' % (binascii.hexlify(self.recv_buf),)) return self.not_match_return(self.recv_buf) utc_time = struct.unpack('<I', out_buf[:4])[0] client_id = struct.unpack('<I', out_buf[4:8])[0] connection_id = struct.unpack('<I', out_buf[8:12])[0] time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('auth_sha1_v4: wrong timestamp, time_dif %d, data %s' % (time_dif, binascii.hexlify(out_buf),)) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(client_id, connection_id): self.has_recv_header = True out_buf = out_buf[12:] self.client_id = client_id self.connection_id = connection_id else: logging.info('auth_sha1_v4: auth fail, data %s' % (binascii.hexlify(out_buf),)) return self.not_match_return(self.recv_buf) self.recv_buf = self.recv_buf[length:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: crc = struct.pack('<H', binascii.crc32(self.recv_buf[:2]) & 0xFFFF) if crc != self.recv_buf[2:4]: self.raw_trans = True logging.info('auth_sha1_v4: wrong crc') if self.decrypt_packet_num == 0: logging.info('auth_sha1_v4: wrong crc') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') length = struct.unpack('>H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' if self.decrypt_packet_num == 0: logging.info('auth_sha1_v4: over size') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') if length > len(self.recv_buf): break if struct.pack('<I', zlib.adler32(self.recv_buf[:length - 4]) & 0xFFFFFFFF) != self.recv_buf[length - 4:length]: logging.info('auth_sha1_v4: checksum error, data %s' % (binascii.hexlify(self.recv_buf[:length]),)) self.raw_trans = True self.recv_buf = b'' if self.decrypt_packet_num == 0: return (b'E'*2048, False) else: raise Exception('server_post_decrype data uncorrect checksum') pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('>H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if pos == length - 4: sendback = True if out_buf: self.server_info.data.update(self.client_id, self.connection_id) self.decrypt_packet_num += 1 return (out_buf, sendback)
def server_decode(self, buf): if self.handshake_status == -1: return (buf, True, False) if (self.handshake_status & 4) == 4: ret = b'' self.recv_buffer += buf while len(self.recv_buffer) > 5: if ord(self.recv_buffer[0]) != 0x17 or ord( self.recv_buffer[1]) != 0x3 or ord( self.recv_buffer[2]) != 0x3: logging.info("data = %s" % (binascii.hexlify(self.recv_buffer))) raise Exception('server_decode appdata error') size = struct.unpack('>H', self.recv_buffer[3:5])[0] if len(self.recv_buffer) < size + 5: break ret += self.recv_buffer[5:size + 5] self.recv_buffer = self.recv_buffer[size + 5:] return (ret, True, False) if (self.handshake_status & 1) == 1: self.recv_buffer += buf buf = self.recv_buffer verify = buf if len(buf) < 11: raise Exception('server_decode data error') if not match_begin(buf, b"\x14" + self.tls_version + b"\x00\x01\x01"): #ChangeCipherSpec raise Exception('server_decode data error') buf = buf[6:] if not match_begin( buf, b"\x16" + self.tls_version + b"\x00"): #Finished raise Exception('server_decode data error') verify_len = struct.unpack('>H', buf[3:5])[0] + 1 # 11 - 10 if len(verify) < verify_len + 10: return (b'', False, False) if hmac.new(self.server_info.key + self.client_id, verify[:verify_len], hashlib.sha1).digest( )[:10] != verify[verify_len:verify_len + 10]: raise Exception('server_decode data error') self.recv_buffer = verify[verify_len + 10:] status = self.handshake_status self.handshake_status |= 4 ret = self.server_decode(b'') return ret #raise Exception("handshake data = %s" % (binascii.hexlify(buf))) self.recv_buffer += buf buf = self.recv_buffer ogn_buf = buf if len(buf) < 3: return (b'', False, False) if not match_begin(buf, b'\x16\x03\x01'): return self.decode_error_return(ogn_buf) buf = buf[3:] header_len = struct.unpack('>H', buf[:2])[0] if header_len > len(buf) - 2: return (b'', False, False) self.recv_buffer = self.recv_buffer[header_len + 5:] self.handshake_status = 1 buf = buf[2:header_len + 2] if not match_begin(buf, b'\x01\x00'): #client hello logging.info("tls_auth not client hello message") return self.decode_error_return(ogn_buf) buf = buf[2:] if struct.unpack('>H', buf[:2])[0] != len(buf) - 2: logging.info("tls_auth wrong message size") return self.decode_error_return(ogn_buf) buf = buf[2:] if not match_begin(buf, self.tls_version): logging.info("tls_auth wrong tls version") return self.decode_error_return(ogn_buf) buf = buf[2:] verifyid = buf[:32] buf = buf[32:] sessionid_len = ord(buf[0]) if sessionid_len < 32: logging.info("tls_auth wrong sessionid_len") return self.decode_error_return(ogn_buf) sessionid = buf[1:sessionid_len + 1] buf = buf[sessionid_len + 1:] self.client_id = sessionid sha1 = hmac.new(self.server_info.key + sessionid, verifyid[:22], hashlib.sha1).digest()[:10] utc_time = struct.unpack('>I', verifyid[:4])[0] time_dif = common.int32((int(time.time()) & 0xffffffff) - utc_time) if self.server_info.obfs_param: try: self.max_time_dif = int(self.server_info.obfs_param) except: pass if self.max_time_dif > 0 and (time_dif < -self.max_time_dif or time_dif > self.max_time_dif \ or common.int32(utc_time - self.server_info.data.startup_time) < -self.max_time_dif / 2): logging.info("tls_auth wrong time") return self.decode_error_return(ogn_buf) if sha1 != verifyid[22:]: logging.info("tls_auth wrong sha1") return self.decode_error_return(ogn_buf) if self.server_info.data.client_data.get(verifyid[:22]): logging.info("replay attack detect, id = %s" % (binascii.hexlify(verifyid))) return self.decode_error_return(ogn_buf) self.server_info.data.client_data.sweep() self.server_info.data.client_data[verifyid[:22]] = sessionid if len(self.recv_buffer) >= 11: ret = self.server_decode(b'') return (ret[0], True, True) # (buffer_to_recv, is_need_decrypt, is_need_to_encode_and_send_back) return (b'', False, True)