def encrypt_conn_data(cls, conn_id, data): if not SysConfig.is_proto_encrypt(): return RET_OK, '', data if type(data) is not bytes: data = bytes_utf8(str(data)) len_src = len(data) mod_tail_len = (len_src % 16) # AES 要求源数据长度是16的整数倍, 不足的话要补0 if mod_tail_len != 0: data += (b'\x00' * (16 - mod_tail_len)) aes_cryptor = FutuConnMng.get_conn_aes_cryptor(conn_id) if aes_cryptor: data = aes_cryptor.encrypt(data) # 增加一个16字节的数据块(目前只有最后一个字节有用),如果对原数据有补数据,记录原数据最后一个数据块真实长度 data_tail = b'\x00' * 15 + bytes_utf8(chr(mod_tail_len)) data_tail = data_tail[-16:] data += data_tail return RET_OK, '', data return RET_ERROR, 'invalid connid', data
def decrypt_conn_data(cls, conn_id, data): if not SysConfig.is_proto_encrypt(): return RET_OK, '', data # tail的未尾字节记录解密数据的最一个数据块真实的长度 data_real = data[:len(data) - 16] data_tail = data[-1:] import struct mem_tmp = b'\0\0\0' + data_tail tail_real_len = struct.unpack(">L", mem_tmp)[0] # tail_real_len = int.from_bytes(data_tail, 'little') aes_cryptor = FutuConnMng.get_conn_aes_cryptor(conn_id) if aes_cryptor: if IS_PY2: de_data = aes_cryptor.decrypt(str(data_real)) else: de_data = aes_cryptor.decrypt(data_real) # 去掉在加密前增加的额外数据 if tail_real_len != 0: cut_len = 16 - tail_real_len de_data = de_data[0:len(de_data) - cut_len] return RET_OK, '', de_data return RET_ERROR, 'AES decrypt error, conn_id:{}'.format(conn_id), data
from futu import * from futu.common.constant import ProtoFMT from futu.common.sys_config import SysConfig from futu.quote.open_quote_context import OpenQuoteContext SysConfig.set_proto_fmt(ProtoFMT.Protobuf) quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111) quote_ctx.close()
def is_conn_encrypt(cls, conn_id): conn_info = cls.get_conn_info(conn_id) if conn_info: return conn_info['is_encrypt'] return SysConfig.is_proto_encrypt()