From 32e6af1ae84bf43b4a42bbe92df1724329be7ea5 Mon Sep 17 00:00:00 2001 From: sangge <2251250136@qq.com> Date: Wed, 29 Nov 2023 16:17:06 +0800 Subject: [PATCH] feat: init repo --- CoreAlgorithm.py | 485 +++++++++++++++++++++++++++++++++++++++++++ DataSearch.py | 265 ++++++++++++++++++++++++ background.png | Bin 0 -> 175359 bytes encoding.py | 162 +++++++++++++++ note.txt | 10 + server_demo.py | 181 ++++++++++++++++ util.py | 414 +++++++++++++++++++++++++++++++++++++ 安全多方服务器.py | 510 ++++++++++++++++++++++++++++++++++++++++++++++ 数据提供方_new.py | 387 +++++++++++++++++++++++++++++++++++ 数据查询方_new.py | 417 +++++++++++++++++++++++++++++++++++++ 10 files changed, 2831 insertions(+) create mode 100644 CoreAlgorithm.py create mode 100644 DataSearch.py create mode 100644 background.png create mode 100644 encoding.py create mode 100644 note.txt create mode 100644 server_demo.py create mode 100644 util.py create mode 100644 安全多方服务器.py create mode 100644 数据提供方_new.py create mode 100644 数据查询方_new.py diff --git a/CoreAlgorithm.py b/CoreAlgorithm.py new file mode 100644 index 0000000..fe1eaa0 --- /dev/null +++ b/CoreAlgorithm.py @@ -0,0 +1,485 @@ +import random +from collections.abc import Mapping +from encoding import EncodedNumber +from util import invert, powmod, getprimeover + +DEFAULT_KEYSIZE = 1024 # 定义默认的二进制数长度 + + +def generate_paillier_keypair(private_keyring=None, n_length=DEFAULT_KEYSIZE): # 生成公钥和私钥的函数 + # 生成 Paillier 密钥对函数 + p = q = n = None # 初始化素数 p, q 和计算结果 n + length = 0 # 初始化计算结果 n 的长度 (即用二进制表示 n 所需要的二进制位数) + + while length != n_length: # 循环直至计算结果 n 的长度达到指定长度 n_length + p = getprimeover(n_length // 2) # 随机生成一个 (n_length//2) 长的素数 p + q = p + while q == p: + # 确保 q 与 p 不相等 + q = getprimeover(n_length // 2) # 随机生成一个 (n_length//2) 长的素数 q + n = p * q # 计算 n,即两个素数乘积 + length = n.bit_length() # 计算 n 的二进制长度 + + # 创建公钥对象 + public_key = PaillierPublicKey(n) + # 创建私钥对象 + private_key = PaillierPrivateKey(public_key, p, q) + + if private_keyring is not None: # 如果传入了私钥环对象,则将私钥添加到私钥环中 + private_keyring.add(private_key) + + return public_key, private_key # 返回公钥和私钥 + + +class PaillierPublicKey(object): # 定义公钥类 + def __init__(self, n): + self.g = n + 1 + self.n = n # 公钥的模数 + self.nsquare = n * n # n的平方 + self.max_int = n // 3 - 1 # 公钥的一个属性(限制可加密/解密的最大整数值) + + def __repr__(self): # 用于打印出该类的对象 + public_key_hash = hex(hash(self))[2:] + return "".format(public_key_hash[:10]) # 返回表示对象的字符串 + + def __eq__(self, other): # 用于比较两个对象是否相等,并返回比较结果 + return self.n == other.n + + def __hash__(self): # 用于返回n的Hash值 + return hash(self.n) + + def get_n_and_g(self): # 获取该公钥的 n 和 g 的值 + return self.n, self.g + + def raw_encrypt(self, plaintext, r_value=None): # 用于返回加密后的密文,其中r_value可给随机数赋值 + if not isinstance(plaintext, int): # 判断plaintext是否是整数 + raise TypeError('明文不是整数,而是: %s' % type(plaintext)) + + if self.n - self.max_int <= plaintext < self.n: # 对于非常大的明文,使用特殊的计算方法进行加密: + neg_plaintext = self.n - plaintext # = abs(plaintext - nsquare) + neg_ciphertext = (self.n * neg_plaintext + 1) % self.nsquare + nude_ciphertext = invert(neg_ciphertext, self.nsquare) + else: # 如果不是非常大的明文: + nude_ciphertext = (self.n * plaintext + 1) % self.nsquare # (n + 1)^plaintext = n * plaintext + 1 mod n^2 + + # 生成一个随机数,其值为r_value。如果r_value没有值,则r随机: + r = r_value or self.get_random_lt_n() + + obfuscator = powmod(r, self.n, self.nsquare) # (r ^ n) mod n^2 + return (nude_ciphertext * obfuscator) % self.nsquare # 返回加密后的密文 + + def get_random_lt_n(self): # 返回一个1——n间的随机整数 + return random.SystemRandom().randrange(1, self.n) + + def encrypt(self, value, precision=None, r_value=None): # value表示要加密的值,precision是加密精度,r_value是随机数 + # 判断value是否是EncodedNumber类型,如果是则直接赋值给encoding;如果不是,则对value进行编码 + if isinstance(value, EncodedNumber): + encoding = value + else: + encoding = EncodedNumber.encode(self, value, precision) + return self.encrypt_encoded(encoding, r_value) + + def encrypt_encoded(self, encoding, r_value): # 将已编码的数值对象转换为加密后的数值对象,并可以选择进行混淆处理 + obfuscator = r_value or 1 # 为随机数r_value,没有则默认为1 + ciphertext = self.raw_encrypt(encoding.encoding, r_value=obfuscator) + encrypted_number = EncryptedNumber(self, ciphertext, encoding.exponent) + + """ + PS:默认生成情况下(不输入随机数r_value的情况下): + encrypt中的随机数r_value为:None + raw_encrypt中的随机数为:1 + encrypt_encoded中的随机数为:None + """ + + if r_value is None: # 结合上述注释,可知:密文混淆函数是会默认执行的 + encrypted_number.obfuscate() # 如果encrypt_encoded没有随机数r_value,则进行密文混淆处理obfuscate() + + return encrypted_number + + +class PaillierPrivateKey(object): # 私钥 + def __init__(self, public_key, p, q): + if not p * q == public_key.n: # 如果p * q 不等于 公钥的n,则说明出错 + raise ValueError("所给公钥与p,q不匹配!") + if p == q: # p,q相同 + raise ValueError("p,q不能相同!") + self.public_key = public_key + + # 给self的p q赋值: + if q < p: # 默认是p 大于等于 q + self.p = q + self.q = p + else: + self.p = p + self.q = q + self.psquare = self.p * self.p + self.qsquare = self.q * self.q + self.p_inverse = invert(self.p, self.q) # 计算p mod q 的乘法逆元 + + self.hp = self.h_function(self.p, self.psquare) # p mod p方 + self.hq = self.h_function(self.q, self.qsquare) # q mod q方 + + def __repr__(self): # 用于打印出该类的对象 + pub_repr = repr(self.public_key) + return "".format(pub_repr) + + def decrypt(self, encrypted_number): # 解密密文,并返回明文 + # 执行下面这个语句前的类型为EncryptedNumber,执行完毕后类型为EncodedNumber(中间会变为int型的ciphertext): + encoded = self.decrypt_encoded(encrypted_number) + return encoded.decode() + + def decrypt_encoded(self, encrypted_number, Encoding=None): # 用于解密密文并返回解密后的EncodedNumber类型 + # 检查输入信息是否是EncryptedNumber参数,如果不是: + if not isinstance(encrypted_number, EncryptedNumber): + raise TypeError('参数应该是EncryptedNumber,' + ' 参数不能为: %s' % type(encrypted_number)) + + if self.public_key != encrypted_number.public_key: # 如果公钥与加密数字的公钥不一致 + raise ValueError('加密信息不能被不同的公钥进行加密!') + + if Encoding is None: # 将Encoding设置为未赋值的EncodedNumber变量 + Encoding = EncodedNumber + + """提取 encrypted_number 中的 ciphertext + 这里是禁用安全模式, + 所以是直接提取ciphertext, + 随后调用raw_decrypt函数对ciphertext进行处理:""" + encoded = self.raw_decrypt(encrypted_number.ciphertext(be_secure=False)) + + return Encoding(self.public_key, encoded, + encrypted_number.exponent) + + def raw_decrypt(self, ciphertext): # 对密文进行原始解密 + if not isinstance(ciphertext, int): # 如果所给的密文不是int型 + raise TypeError('密文应该是int型, 而不是: %s' % + type(ciphertext)) + + # 将解密结果存放在p和q中,并将p q进行合并: + decrypt_to_p = self.l_function(powmod(ciphertext, self.p - 1, self.psquare), self.p) * self.hp % self.p + decrypt_to_q = self.l_function(powmod(ciphertext, self.q - 1, self.qsquare), self.q) * self.hq % self.q + return self.crt(decrypt_to_p, decrypt_to_q) + + def h_function(self, x, xsquare): # 计算并返回h函数值[用于中国剩余定理] + return invert(self.l_function(powmod(self.public_key.g, x - 1, xsquare), x), x) + + def l_function(self, mju, p): # 计算并返回l值(算L(μ) ) + return (mju - 1) // p + + def crt(self, mp, mq): # 实现中国剩余定理(Chinese remainder theorem) + u = (mq - mp) * self.p_inverse % self.q + return mp + (u * self.p) + + def __eq__(self, other): # 判断两个对象的 q 与 p 是否相等 + return self.p == other.p and self.q == other.q + + def __hash__(self): # 计算 p 与 q 元组的哈希值 + return hash((self.p, self.q)) + + +class PaillierPrivateKeyring(Mapping): # 私钥环类,并继承了Mapping类 + def __init__(self, private_keys=None): # 初始化私钥环对象(私钥环列表) + if private_keys is None: + private_keys = [] + + # 将私钥和公钥进行组合,并存储在私钥环中: + public_keys = [k.public_key for k in private_keys] + self.__keyring = dict(zip(public_keys, private_keys)) + + def __getitem__(self, key): # 通过公钥,来查找私钥环中对应的私钥 + return self.__keyring[key] + + def __len__(self): # 存储的私钥数量 + return len(self.__keyring) + + def __iter__(self): # 遍历私钥环中的公钥 + return iter(self.__keyring) + + def __delitem__(self, public_key): # 删除与公钥对应的私钥 + del self.__keyring[public_key] + + def add(self, private_key): # 向私钥环中添加私钥 + if not isinstance(private_key, PaillierPrivateKey): # 对要添加的私钥进行判断 + raise TypeError("私钥应该是PaillierPrivateKey类型, " + "而不是 %s" % type(private_key)) + self.__keyring[private_key.public_key] = private_key # 将该公钥和对用的私钥一块儿加入到私钥环中 + + def decrypt(self, encrypted_number): # 对密文进行解密 + relevant_private_key = self.__keyring[encrypted_number.public_key] # 在私钥环中获取对应的私钥 + return relevant_private_key.decrypt(encrypted_number) # 返回加密结果 + + +class EncryptedNumber(object): # 浮点数或整数的Pailier加密 + """ + 1. D(E(a) * E(b)) = a + b + 2. D(E(a)**b) = a * b + """ + + def __init__(self, public_key, ciphertext, exponent=0): + self.public_key = public_key + self.__ciphertext = ciphertext # 密文 + self.exponent = exponent # 用于表示指数 + self.__is_obfuscated = False # 用于表示数据是否被混淆 + if isinstance(self.ciphertext, EncryptedNumber): # 如果密文是EncryptedNumber + raise TypeError('密文必须是int型') + if not isinstance(self.public_key, PaillierPublicKey): # 如果公钥不是PaillierPublicKey + raise TypeError('公钥必须是PaillierPublicKey') + + def __add__(self, other): # 运算符重载,重载为EncryptedNumber与(EncryptedNumber/整数/浮点数)的加法 + if isinstance(other, EncryptedNumber): + return self._add_encrypted(other) + elif isinstance(other, EncodedNumber): + return self._add_encoded(other) + else: + return self._add_scalar(other) + + def __radd__(self, other): # 反加,处理整数/浮点数与EncryptedNumber之间的加法 + return self.__add__(other) + + def __mul__(self, other): # 运算符重载,重载为EncryptedNumber与(整数/浮点数)的乘法 + # 判断other对象是否是EncryptedNumber,如果是: + if isinstance(other, EncryptedNumber): + raise NotImplementedError('EncryptedNumber 与 EncryptedNumber 之间不能相乘!') + + if isinstance(other, EncodedNumber): + encoding = other + else: + encoding = EncodedNumber.encode(self.public_key, other) + product = self._raw_mul(encoding.encoding) # 重新更新乘积 + exponent = self.exponent + encoding.exponent # 重新更新指数 + return EncryptedNumber(self.public_key, product, exponent) + + def __rmul__(self, other): # 反乘,处理整数/浮点数与EncryptedNumber之间的乘法 + return self.__mul__(other) + + def __sub__(self, other): # 运算符重载,重载为EncryptedNumber与(EncryptedNumber/整数/浮点数)的减法 + return self + (other * -1) + + def __rsub__(self, other): # 处理整数/浮点数与EncryptedNumber之间的减法 + return other + (self * -1) + + def __truediv__(self, scalar): # 运算符重载,重载为EncryptedNumber与(EncryptedNumber/整数/浮点数)的除法 + return self.__mul__(1 / scalar) + + def __invert__(self): # 运算符重载~(对 数 的取反) + return self * (-1) + + # def __pow__(self, exponent): # 运算符重载 ** (对密文的幂函数) + # if not isinstance(exponent, int): # 如果输入有问题 + # print("指数应输入 整数 标量!") + # else: + # result = self + # for i in [1, exponent]: + # result *= self + # return result + # # 原本的幂运算 ** ;return self.value ** exponent + + def ciphertext(self, be_secure=True): # 用于混淆密文,并返回混淆后的密文 + """ + EncryptedNumber类的一个方法ciphertext,用于返回该对象的密文。 + 在Paillier加密中,为了提高计算性能,加法和乘法操作进行了简化, + 避免对每个加法和乘法结果进行随机数的加密操作。 + 这样会使得内部计算快速,但会暴露一部分信息。 + 此外,为了保证安全,如果需要与其他人共享密文,应该使用be_secure=True。 + 这样,如果密文还没有被混淆,会调用obfuscate方法对其进行混淆操作。 + """ + if be_secure and not self.__is_obfuscated: # 如果密文没有被混淆,则进行混淆操作 + self.obfuscate() + return self.__ciphertext + + def decrease_exponent_to(self, new_exp): # 返回一个指数较低但大小相同的数(即返回一个同值的,但指数较低的EncryptedNumber) + if new_exp > self.exponent: + raise ValueError('新指数值 %i 应比原指数 %i 小! ' % (new_exp, self.exponent)) + + multiplied = self * pow(EncodedNumber.BASE, self.exponent - new_exp) # 降指数后的乘积 + multiplied.exponent = new_exp # 降指数后的新指数 + return multiplied + + def obfuscate(self): # 混淆密文 + r = self.public_key.get_random_lt_n() # 生成一个(1——n)间的随机数r,不 >= r + r_pow_n = powmod(r, self.public_key.n, self.public_key.nsquare) # (r ^ n) mod n^2 + self.__ciphertext = self.__ciphertext * r_pow_n % self.public_key.nsquare # 对原密文进行处理 + self.__is_obfuscated = True # 用于判断密文是否被混淆 + + def _add_scalar(self, scalar): # 执行EncodedNumber与标量(整型/浮点型)相加的操作 + encoded = EncodedNumber.encode(self.public_key, scalar, + max_exponent=self.exponent) + return self._add_encoded(encoded) + + def _add_encoded(self, encoded): # 对EncodedNumber与标量encoded加法编码 + # 返回 E(a + b) + + if self.public_key != encoded.public_key: # 如果公钥与编码公钥不相同 + raise ValueError("不能使用不同的公钥,对数字进行编码!") + + a, b = self, encoded + # 对指数处理(使指数相同): + if a.exponent > b.exponent: + a = self.decrease_exponent_to(b.exponent) + elif a.exponent < b.exponent: + b = b.decrease_exponent_to(a.exponent) + + encrypted_scalar = a.public_key.raw_encrypt(b.encoding, 1) # 用公钥加密b.encoding后的标量 + + sum_ciphertext = a._raw_add(a.ciphertext(False), encrypted_scalar) # 进行相加操作 + return EncryptedNumber(a.public_key, sum_ciphertext, a.exponent) + + def _add_encrypted(self, other): # 对EncodedNumber与EncodedNumber加法加密 + if self.public_key != other.public_key: + raise ValueError("不能使用不同的公钥,对数字进行加密!") + + # 对指数处理(使指数相同): + a, b = self, other + if a.exponent > b.exponent: + a = self.decrease_exponent_to(b.exponent) + elif a.exponent < b.exponent: + b = b.decrease_exponent_to(a.exponent) + + sum_ciphertext = a._raw_add(a.ciphertext(False), b.ciphertext(False)) + return EncryptedNumber(a.public_key, sum_ciphertext, a.exponent) + + def _raw_add(self, e_a, e_b): # 对加密后的a,b直接进行相加,并返回未加密的结果 + return e_a * e_b % self.public_key.nsquare + + def _raw_mul(self, plaintext): # 对密文进行乘法运算,并返回未加密的结果 + # 检查乘数是否为int型: + if not isinstance(plaintext, int): + raise TypeError('期望密文应该是int型, 而不是 %s' % type(plaintext)) + + # 如果乘数是负数,或乘数比公钥的模(n)大: + if plaintext < 0 or plaintext >= self.public_key.n: + raise ValueError('超出可计算范围: %i' % plaintext) + + if self.public_key.n - self.public_key.max_int <= plaintext: + # 如果数据很大,则先反置一下再进行运算: + neg_c = invert(self.ciphertext(False), self.public_key.nsquare) + neg_scalar = self.public_key.n - plaintext + return powmod(neg_c, neg_scalar, self.public_key.nsquare) + else: + return powmod(self.ciphertext(False), plaintext, self.public_key.nsquare) + + def increment(self): # 定义自增运算 + return self + 1 + + def decrement(self): # 定义自减运算 + return self + 1 + + def cal_sum(self, *args): + result = 0 # 将初始值设置为0 + for i in args: + if not isinstance(i, (int, float, EncryptedNumber)): + raise TypeError('期望密文应该是int/float/EncryptedNumber型, 而不是 %s' % type(i)) + if isinstance(i, int or float): # 如果是 int 或 float 明文型,则先将明文加密在进行运算 + result += self.public_key.encrypt(i) + else: + result += i # 第一次循环:标量与密文相加;后面的循环,密文与密文相加 + return result + + def average(self, *args): # 定义求平均值 + total_sum = self.cal_sum(*args) # 计算总和total是<__main__.EncryptedNumber object at 0x000002AB74FB9850> + + # # 如果总数超过了可计算范围 + # if total_sum > 91000: + # raise ValueError('超出可计算范围: %i' % total_sum) + + count = 0 # 定义count,用来统计参数的个数 + for _ in args: + count += 1 # count++ + return total_sum / count + + def weighted_average(*args): # 定义加权平均 + """ PS: + args[0]: <__main__.EncryptedNumber object at 0x000001F7C1B6A610> + args[1]: 第一个参数 + args[2]: 给第一个参数设置的权值 + 。。。。。。 + """ + total_weight = sum(args[2::2]) # 计算权值的总和(使用切片操作从参数列表中取出索引为参数权值的元素) + if total_weight != 1: + raise TypeError("加权平均算法的权值设置错误!请重新设置!") + else: + # 计算加权和,其中: for i in range(0, len(args), 2) 表示以2为步长,从0递增,直到 i >= len(args)时: + result = sum(args[i] * args[i + 1] for i in range(1, len(args), 2)) + return result + + def reset(self): # 定义复位(置0运算) + zero = self.public_key.encrypt(0) # 用公钥对0进行加密 + return zero + + def calculate_variance(self, *args): # 定义求方差 + mean = self.average(*args) # 均值 + count = 0 # 定义count,用来统计参数的个数 + for _ in args: + count += 1 # count++ + variance = sum((x - mean) ** 2 for x in args) / (count - 1) + return variance + + # def IsZero(self): # 判断该数是否为0 + # ZERO = self + # zero = ZERO.public_key.encrypt(0) # 用公钥对0进行加密 + # flag = False # 用于判断该数是否为0(默认不为0) + # + # if self == zero: + # flag = True + # return flag + + # def POW(self, num): # 定义幂运算 + # if not isinstance(num, int): # 如果输入有问题 + # print("指数应输入 整数 标量!") + # else: + # result = self + # print(num) + # for i in [1, num]: + # result *= self + # return result + + +# def get_certificate(public_key): +# # 获得公钥的PEM编码的二进制形式 +# public_bytes = public_key.public_bytes( +# encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) +# +# # 获得数字证书 +# cert = (public_bytes, hashlib.sha256(public_bytes).hexdigest()) # 元祖类型 +# return cert + + +if __name__ == '__main__': # 主函数 + Public_Key, Private_Key = generate_paillier_keypair() # 随机生成1024长的公钥和私钥 + x = 90000.23 + y = 90 + z = 0.5 + x_encrypted = Public_Key.encrypt(x) # 加密后的x + y_encrypted = Public_Key.encrypt(y) # 加密后的y + z_encrypted = Public_Key.encrypt(z) # 加密后的z + t_encrypted = x_encrypted + y_encrypted * 0.5 # 在x,y保密的情况下计算t,得到加密后的t(t_encrypted) + + # x_encrypted = x_encrypted.increment() # 自增 + # y_encrypted = y_encrypted.decrement() # 自减 + + # print(x_encrypted != y_encrypted) # 不相等 + # print(x_encrypted == y_encrypted) # 相等 + + # print(Private_Key.decrypt(~x_encrypted) ) # 取反 + + # total = x_encrypted.cal_sum(x_encrypted, y_encrypted, 0.5) # 求和函数 + # print("密文之和为:", Private_Key.decrypt(total)) + + # avg = x_encrypted.average(y_encrypted, z_encrypted, z_encrypted) # 求平均值函数 + # print("密文的平均值为:", Private_Key.decrypt(avg) ) # 只能对0~90090.73的数进行除法运算(除不尽) + + # weight_average = x_encrypted.weighted_average(x_encrypted, 0.1, y_encrypted, 0.3, z_encrypted, 0.6) # 加权平均函数 + # print("加权平均结果为:", Private_Key.decrypt(weight_average)) + + # variance = x_encrypted.calculate_variance(x_encrypted, y_encrypted) #求方差 + # print("方差为:", Private_Key.decrypt(variance)) + + # z_encrypted = z_encrypted.reset() # 复位函数 + # print("z复位后的结果为:", Private_Key.decrypt(z_encrypted) ) + + # print(x_encrypted ** x) # 相当于print(x_encrypted.POW(2) ) + # print(x_encrypted > y_encrypted) + + # print(type(Public_Key)) + # print(Public_Key) + + print(f"x + y * 0.5的结果是:{Private_Key.decrypt(t_encrypted)}") # 打印出t diff --git a/DataSearch.py b/DataSearch.py new file mode 100644 index 0000000..0c1f6dc --- /dev/null +++ b/DataSearch.py @@ -0,0 +1,265 @@ +import re +import pymysql + + +# 拆分sql对象 +def extract_tables(sql_statement): + # 使用正则表达式匹配FROM关键字之后的表名以及逗号分隔的表名: + pattern = r'FROM\s+([\w\s,]+)' + matches = re.findall(pattern, sql_statement, re.IGNORECASE) + # 提取逗号分隔的表名,并按逗号进行分割 + tabs = re.split(',', matches[0].strip()) + # 处理每个表名,去除空格和其他无关字符 + cleaned_tables = [] + for tab in tabs: + cleaned_tab = tab.strip() + if ' ' in cleaned_tab: + cleaned_tab = cleaned_tab.split()[0] + cleaned_tables.append(cleaned_tab) + return cleaned_tables # 返回列表 + + +# 拆分sql +def divide_sql(sql): + """ + 例如sql = "SELECT a FROM data1, data2, data3 WHERE a = b ORDER BY misc" + 拆分原语句 + """ + parts = re.split(r'(?i)from\s', sql) # 拆分"from "【无论大小写】 + head = parts[0] + "from " # SELECT a FROM + divide_sqls = [] + + if re.search(r'where', parts[1], flags=re.IGNORECASE): + data = re.split(r'(?i) where', parts[1]) # 拆分" where"【无论大小写】 + tail = " where" + data[1] # WHERE a = b ORDER BY misc + # message_p = "涉及到的数据源有:" + # print(message_p) + # time.sleep(sleep_time) + # + # message_p = data[0] + # print(message_p) # data1, data2, data3 + # time.sleep(sleep_time) + divide_providers = data[0].split(", ") + # total = len(divide_providers) + # message_p = "拆分结果如下:" + # print(message_p) + + for i in range(len(divide_providers)): + divide_sqls.append(head + divide_providers[i] + tail) + # message_p = str(i + 1) + ":" + divide_sqls[i] + # print(message_p) + else: + data = parts[1] # data1,data2,data3 + divide_providers = data.split(",") + for i in range(len(divide_providers)): + divide_sqls.append(head + divide_providers[i]) + # message_p = str(i + 1) + ":" + divide_sqls[i] + # print(message_p) + return divide_sqls + + +class SelectDatabase: # 定义类 + def __init__(self, database): + self.database = database # 赋值数据库名称 + + def ret_hospital(self): # 定义函数,返回字典——医院(HOS)这个表 + # 连接服务器Server的数据库: + db = pymysql.connect(host='localhost', user='root', password='111111', db=f'{self.database}', charset='utf8') + # 使用操作游标: + cursor = db.cursor() + sql = """SELECT * FROM HOS""" + cursor.execute(sql) + results = cursor.fetchall() # 获取查询结果的所有数据 + hospital_dict = {} # 创建一个空字典 + + # 遍历查询结果,将每条消息数据存储到字典中: + for row in results: + hos_id = row[0] # 医院编号(HOS_ID) + hos_name = row[1] # 医院名称(HOS_NAME) + hos_add = row[2] # 医院地址(HOS_ADD) + hos_tel = row[3] # 医院电话(HOS_TEL) + # hospital_dict["医院编号"] = hos_id + # hospital_dict["医院名称"] = hos_name + # hospital_dict["医院地址"] = hos_add + # hospital_dict["医院电话"] = hos_tel + # # 打印字典内容 + # print(hospital_dict) + """ 注释的输出形式: + {'医院编号': '001', '医院名称': '极光医院', '医院地址': '千里市广大区极光街道1-1', '医院电话': '023-6296666'} + {'医院编号': '002', '医院名称': '风舱医院', '医院地址': '风火市舱山区飞光街道1-1', '医院电话': '023-6286666'} + """ + + # 将每个属性的值存储在对应的列表中 + hospital_dict.setdefault("医院编号", []).append(hos_id) + hospital_dict.setdefault("医院名称", []).append(hos_name) + hospital_dict.setdefault("医院地址", []).append(hos_add) + hospital_dict.setdefault("医院电话", []).append(hos_tel) + + db.close() + """ 当前返回的字典形式: + {'医院编号': ['001', '002'], + '医院名称': ['极光医院', '风舱医院'], + '医院地址': ['千里市广大区极光街道1-1', + '风火市舱山区飞光街道1-1'], + '医院电话': ['023-6296666', '023-6286666']} + """ + # 返回字典 + return hospital_dict + + def ret_doctor(self): # 定义函数,返回字典——医生(DOC)这个表 + # 连接服务器Server的数据库: + db = pymysql.connect(host='localhost', user='root', password='111111', db=f'{self.database}', charset='utf8') + # 使用操作游标: + cursor = db.cursor() + sql = """SELECT * FROM DOC""" + cursor.execute(sql) + results = cursor.fetchall() # 获取查询结果的所有数据 + doctor_dict = {} # 创建一个空字典 + + # 遍历查询结果,将每条消息数据存储到字典中: + for row in results: + doc_id = row[0] # 医生编号(DOC_ID) + doc_name = row[1] # 医生名称(DOC_NAME) + doc_tel = row[2] # 医生电话(DOC_TEL) + doc_qua = row[3] # 医院资质(DOC_QUA) + # hospital_dict["医生编号"] = doc_id + # hospital_dict["医生名称"] = doc_name + # hospital_dict["医院地址"] = doc_tel + # hospital_dict["医院电话"] = doc_qua + # # 打印字典内容 + # print(doctor_dict) + + # 将每个属性的值存储在对应的列表中 + doctor_dict.setdefault("医院编号", []).append(doc_id) + doctor_dict.setdefault("医院名称", []).append(doc_name) + doctor_dict.setdefault("医院地址", []).append(doc_tel) + doctor_dict.setdefault("医院电话", []).append(doc_qua) + + db.close() + """ 当前返回的字典形式: + {'医院编号': ['001', '002', '003'], + '医院名称': ['神医华佗', '扁鹊', '还医生'], + '医院地址': ['19666666666', '13666666666', '13546981623'], + '医院电话': ['主任医师', '主任医师', '医师']} + """ + # 返回字典 + return doctor_dict + + def ret_patient(self): # 定义函数,返回字典——病人(PAT)这个表 + # 连接服务器Server的数据库: + db = pymysql.connect(host='localhost', user='root', password='111111', db=f'{self.database}', charset='utf8') + # 使用操作游标: + cursor = db.cursor() + sql = """SELECT * FROM PAT""" + cursor.execute(sql) + results = cursor.fetchall() # 获取查询结果的所有数据 + patient_dict = {} # 创建一个空字典 + + # 遍历查询结果,将每条消息数据存储到字典中: + for row in results: + pat_id = row[0] # 病人编号(PAT_ID) + pat_name = row[1] # 病人姓名(PAT_NAME) + pat_tel = row[2] # 病人电话(PAT_TEL) + # patient_dict["病人编号"] = pat_id + # patient_dict["病人姓名"] = pat_name + # patient_dict["病人电话"] = pat_tel + # # 打印字典内容 + # print(patient_dict) + + # 将每个属性的值存储在对应的列表中 + patient_dict.setdefault("病人编号", []).append(pat_id) + patient_dict.setdefault("病人姓名", []).append(pat_name) + patient_dict.setdefault("病人电话", []).append(pat_tel) + + db.close() + """ 当前返回的字典形式: + {'病人编号': ['001', '002', '003', '004'], + '病人姓名': ['曹操', '蔡桓公', '去还', '刘备'], + '病人电话': ['66666666666', '02666666666', '01234567891', '98765432101']} + """ + # 返回字典 + return patient_dict + + def ret_diagnosis(self): # 定义函数,返回字典——诊断(DIA)这个表 + # 连接服务器Server的数据库: + db = pymysql.connect(host='localhost', user='root', password='111111', db=f'{self.database}', charset='utf8') + # 使用操作游标: + cursor = db.cursor() + sql = """SELECT * FROM DIA""" + cursor.execute(sql) + results = cursor.fetchall() # 获取查询结果的所有数据 + diagnosis_dict = {} # 创建一个空字典 + + # 遍历查询结果,将每条消息数据存储到字典中: + for row in results: + dia_id = row[0] # 诊号(DIA_ID) + doc_id = row[1] # 医生编号(DOC_ID) + pat_id = row[2] # 病人编号(PAT_ID) + time = row[3] # 时间(TIME) + cases = row[4] # 病例(CASES) + symptom = row[5] # 症状(SYMPTOM) + # diagnosis_dict["诊号"] = dia_id + # diagnosis_dict["医生编号"] = doc_id + # diagnosis_dict["病人编号"] = pat_id + # diagnosis_dict["时间"] = time + # diagnosis_dict["病例"] = cases + # diagnosis_dict["症状"] = symptom + # # 打印字典内容 + # print(diagnosis_dict) + + # 将每个属性的值存储在对应的列表中 + diagnosis_dict.setdefault("诊号", []).append(dia_id) + diagnosis_dict.setdefault("医生编号", []).append(doc_id) + diagnosis_dict.setdefault("病人编号", []).append(pat_id) + diagnosis_dict.setdefault("时间", []).append(time) + diagnosis_dict.setdefault("病例", []).append(cases) + diagnosis_dict.setdefault("症状", []).append(symptom) + + db.close() + """ 当前返回的字典形式: + {'诊号': ['001', '002', '003', '004', '005'], + '医生编号': ['001', '001', '002', '003', '003'], + '病人编号': ['001', '001', '002', '003', '004'], + '时间': ['2015.03.04', '2015.05.16', '2016.12.30', '2017.01.15', '2017.01.15'], + '病例': ['小感冒', '慢性头痛', '通风', '中风', '脚部内伤'], '症状': ['突然头痛', '头非常痛,不能睡觉', '怕凉', '伤口大量出血,且发烧', '崴脚,走路痛']} + """ + # 返回字典 + return diagnosis_dict + + def ret_define(self, sql): # 定义函数,返回自定义信息的字典 + # 连接服务器Server的数据库: + db = pymysql.connect(host='localhost', user='root', password='111111', db=f'{self.database}', charset='utf8') + try: + # 使用操作游标: + cursor = db.cursor() + cursor.execute(sql) + results = cursor.fetchall() # 获取查询结果的所有数据 + # tables = extract_tables(sql) # 分离出sql语句中的表名 + + # 遍历查询结果,将每条消息都输出出来: + for row in results: + for i in range(len(row)): + print(f"{row[i]}\t", end="") + print() + + except: + print("查询权限不足!或查询语句出错!") + + +def main(hospital_name): + sql = """SELECT * + FROM HOS, DOC, PAT, DIA + WHERE DOC.DOC_ID = DIA.DOC_ID AND + PAT.PAT_ID = DIA.PAT_ID + """ + hospital_name = hospital_name.replace("\n", "") + if hospital_name == 'xx大学附属医院': + database = SelectDatabase('Hospital1') + database.ret_define(sql) + + elif hospital_name == 'xx阳光社区附属医院': + database = SelectDatabase('Hospital2') + database.ret_define(sql) + + else: + print("暂无记录!") diff --git a/background.png b/background.png new file mode 100644 index 0000000000000000000000000000000000000000..d14f18f0fc9e3206c9bde7e252e12bab192863c0 GIT binary patch literal 175359 zcmXtfbyVEk7wrtz!3QZ;D1$?BcNm=F?ykitZbNa`;_mR_#a)ZLyObiu-SzQ%Z@oW~ ztlZ?TtmK~TbN0UbhASyZp`#F?0002=uhQZw005lX`xXm=dvB3D7b$x`AUjHHI|BgN zF8|wr8y2J3Rd_dV`}a!>;I5Lv|&tBi>DNCdy5t?dfD<&1ZYZ&Aq;k+kM5s zEpzYILeW`ev|gu}M0fofsb2nU89@YlW3`OqV&f$~O&w7RP8>)JcsP1o3a%I%8X5|_ z^FHg3#0TlHB7ndUs9!wV?5h!mO!~HaH;M`!%E7Uvi@nX^=igO|v<2 z$SB~wmEZx2fMz=)BAy%a|9S&rMWD(5_jX9PDLBsD?|*lJ&Iu6A(tM4O_O`0T|8I*l z1TxA2@2ufAP&m8|--#A?nhPyQWeIujkuFmDaAhHMbxjQ+YR`bM^I-6C@nF#275IUq zfjBJiEGz&P06aAUc`KJ$e6qcYb*3ER(hUW2P*Ly@(B zShTz7c!NOmz=F8#6a<17P;yKmVPU)H(MI5hB*-pg9hf!+BAm4hgx1Qt;nIeZd?F4W zF)mtiOT|rq7l%dx&_IBF6eKf%kt6^}@J7{55U7&DRcZU5gOI)xupWy_G8HR~aG6HJ zs0p3|0M8ByfPe#nnF_`8{Fy|obH64c?W=%D(9y#yKin;`1)d5^vgCU`bZ^B3xgeQ% z>q>dsJpEy0ve=s%xvBM__+mk>fs(34XC}Ivt0EpGE{8(=i2;WJ)fR_XBIb7?1kZHU ztf;#dx?I*0pFce~6nX7%3wVJKOiW=~=aNV5GqQ3GgtNdJj^p*rJ<1JLl9>_%W1!Ln z7yB32*ynzR6AWra67>W75lI78OzE_wap9En!H~Gg92P|q^v7F*o+WZwGRg}`E4ON( zh^}4~pn}-+R@82uudFJ+5pT|Q3Oz18P6b3cM_cG0=Lc69LJI%_waD|u{rx~=RV~PJ z5K7_Z)z=9{(u1g8GbwvNWgtROM5wwS$V6Njab!r9dFwh&x{sCs3kwjR7N43%$;t{3 z&mLIoha5IV<|6kCm}+jU{GD3sDxE4S={qsxy{|d z=P64p*(z4vJTBbKt*X(OpR*zLX+x!w(GQN&FHY2&mU5qOKYcVSHx!z%UpA8t^a|rV zV564_SFzL=qZph2Xum9oi54Q=w^Rc=@eeGKnLM^bh(7GWfLX=@N+~_nkI%_uzBLd?EIX@R5+%L~l1Z%!HIC5$ea-+)<#&w14 z>)`35mHkN@a¬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%0AEOk@45b8 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�X zFVFeL@Jy0{)op_%fePw>&3G}B=!b#+{rjYGBP*7#@{)C$R2n2Rx%5uPymEOhv-<5x zx;R<;=L8Sbdxgp^b3#i~^MS`^?(^K4v!D9y6akF1fY+io-+t}UXDrnm2pD^PjKcb; zdc_7$=8Pk*r&>H&NSnm-3E&-cR^~lvT-~tIEBrX3RW^;ob0TLeoAyjlEig3`+r0X0gg8l$NNrPUe7%%8z#2}0gm z3Z9UoKqOXCbb};I>b4VkC&M_U3b{T4aPqHLS}ZO|>iC06k3BwV+GDz#$NEPe3UBc1 z3*P(Q4L2)MX0QXgmho0@%znd$ZMS3kuJ_z_n=!{6KIO@OL;*RuuV9{Z-DPQJfSd36 z3pTHn_wOA(H#Rjd-5jQpoP9_(Jb#Ob&H-PGzD{DHOcltAMOEkg$BClTJ~RE*AlOcR z@Yy9xmkU^S?W(k|d_bS#G(F$=y5d&#vf5pgQb?MTnv9bAs z52}_dtr>YlCTY;VVS&UaCAW@4T0K34OGDRiA7n z=ST0GOauqoYgndO(94fJ^UVE!Ri_)Gub-4TZ_VPW4Z`7=a?xg~!lNVPg^e*2(N=Y+Th8nHPzWU%c9J(}_R_g=N<`Qb)3h>0fj#r|f@d~j zDghw`5p1;|)swwfKUhKQJcu!HyIyHUk=YC0=e!p%9kr5j$B=g3 zX~#YI_zR}@*d4WpbnyN$aQn44-Ks;#nnIBvi22=xALI?L_ba8t&!QA z@CgcD9)84mq2$QM4Vf%L1;swzLHiEcXOG8!GkM@%8SG#5_QH*7mLtd1d$*m^U!VEyWJgX2Z!18aazx}o#Lh)g zln9Qw_uz~}@A7vmS`7P{kpqK~18I_gN3Dfihx}@Uu&_nZ@hCdx}wBnpon9f+5f%VV`DgRnH~|2;@7+6A6o$oN48G z2|*zkJORQHBfEuhK6w#z8^fYHRmg*vbpd?fzVW>>2{*uPnQQghv+N4Ib` zQzx525fJ%Q$f`0+`xl6x#S@tc4D#L}TL4C#I}@i?b3hd=@dkL1j68uLLLrbn#0<*b zESKu$Dme&9@zSi7tT1WrJgg9 !+2L@lhOenwsmqGunSvG85|trIRj`GioY^3q%H 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.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≫& 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 O0000 2n/3 is + negative. The range temp_n/3 < x < 2n/3 allows for overflow + detection. + + Args: + public_key (PaillierPublicKey): public key for which to encode + (this is necessary because :attr:`~PaillierPublicKey.temp_n` + varies). + scalar: an int or float to be encrypted. + If int, it must satisfy abs(*value*) < + :attr:`~PaillierPublicKey.temp_n`/3. + If float, it must satisfy abs(*value* / *precision*) << + :attr:`~PaillierPublicKey.temp_n`/3 + (i.e. if a float is near the limit then detectable + overflow may still occur) + precision (float): Choose exponent (i.e. fix the precision) so + that this number is distinguishable from zero. If `scalar` + is a float, then this is set so that minimal precision is + lost. Lower precision leads to smaller encodings, which + might yield faster computation. + max_exponent (int): Ensure that the exponent of the returned + `EncryptedNumber` is at most this. + + Returns: + EncodedNumber: Encoded form of *scalar*, ready for encryption + against *publickey*. + """ + # Calculate the maximum exponent for desired precision + if precision is None: + if isinstance(scalar, int): + prec_exponent = 0 + elif isinstance(scalar, float): + # Encode with *at least* as much precision as the python float + # What's the base-2 exponent on the float? + bin_flt_exponent = math.frexp(scalar)[1] + + # What's the base-2 exponent of the least significant bit? + # The least significant bit has value 2 ** bin_lsb_exponent + bin_lsb_exponent = bin_flt_exponent - cls.FLOAT_MANTISSA_BITS + + # What's the corresponding base BASE exponent? Round that down. + prec_exponent = math.floor(bin_lsb_exponent / cls.LOG2_BASE) + else: + raise TypeError("Don't know the precision of type %s." + % type(scalar)) + else: + prec_exponent = math.floor(math.log(precision, cls.BASE)) + + # Remember exponents are negative for numbers < 1. + # If we're going to store numbers with a more negative + # exponent than demanded by the precision, then we may + # as well bump up the actual precision. + if max_exponent is None: + exponent = prec_exponent + else: + exponent = min(max_exponent, prec_exponent) + + int_rep = int(round(scalar * pow(cls.BASE, -exponent))) + + if abs(int_rep) > public_key.max_int: + raise ValueError('Integer needs to be within +/- %d but got %d' + % (public_key.max_int, int_rep)) + + # Wrap negative numbers by adding temp_n + return cls(public_key, int_rep % public_key.n, exponent) + + def decode(self): + """Decode plaintext and return the result. + + Returns: + an int or float: the decoded number. N.B. if the number + returned is an integer, it will not be of type float. + + Raises: + OverflowError: if overflow is detected in the decrypted number. + """ + if self.encoding >= self.public_key.n: + # Should be mod temp_n + raise ValueError('Attempted to decode corrupted number') + elif self.encoding <= self.public_key.max_int: + # Positive + mantissa = self.encoding + elif self.encoding >= self.public_key.n - self.public_key.max_int: + # Negative + mantissa = self.encoding - self.public_key.n + else: + raise OverflowError('Overflow detected in decrypted number') + + return mantissa * pow(self.BASE, self.exponent) + + def decrease_exponent_to(self, new_exp): + """Return an `EncodedNumber` with same value but lower exponent. + + If we multiply the encoded value by :attr:`BASE` and decrement + :attr:`exponent`, then the decoded value does not change. Thus + we can almost arbitrarily ratchet down the exponent of an + :class:`EncodedNumber` - we only run into trouble when the encoded + integer overflows. There may not be a warning if this happens. + + This is necessary when adding :class:`EncodedNumber` instances, + and can also be useful to hide information about the precision + of numbers - e.g. a protocol can fix the exponent of all + transmitted :class:`EncodedNumber` to some lower bound(s). + + Args: + new_exp (int): the desired exponent. + + Returns: + EncodedNumber: Instance with the same value and desired + exponent. + + Raises: + ValueError: You tried to increase the exponent, which can't be + done without decryption. + """ + if new_exp > self.exponent: + raise ValueError('New exponent %i should be more negative than' + 'old exponent %i' % (new_exp, self.exponent)) + factor = pow(self.BASE, self.exponent - new_exp) + new_enc = self.encoding * factor % self.public_key.n + return self.__class__(self.public_key, new_enc, new_exp) \ No newline at end of file diff --git a/note.txt b/note.txt new file mode 100644 index 0000000..dda0dc5 --- /dev/null +++ b/note.txt @@ -0,0 +1,10 @@ +编写的sql格式硬性规定: +含有from,多个对象需要用,分割 + +要先定好测试案例,sql语句,然后才方便用if/else,跑结果 + +中央人民医院 +xx阳光社区诊所 +xx大学附属医院 + +select count(*) from xx阳光社区诊所, xx大学附属医院 where diag = "cancer"; \ No newline at end of file diff --git a/server_demo.py b/server_demo.py new file mode 100644 index 0000000..c516a17 --- /dev/null +++ b/server_demo.py @@ -0,0 +1,181 @@ +import wx +import wx.xrc + + +class MyFrame(wx.Frame): + + def __init__(self, parent): + wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"安全多方服务器平台", pos=wx.DefaultPosition, + size=wx.Size(444, 749), + style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) + + self.SetSizeHints(wx.DefaultSize, wx.DefaultSize) + self.SetFont(wx.Font(5, 70, 90, 90, False, "宋体")) + self.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) + + fgSizer1 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer1.SetFlexibleDirection(wx.BOTH) + fgSizer1.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + bSizer11 = wx.BoxSizer(wx.VERTICAL) + + self.m_bitmap11 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size(70, 30), 0) + bSizer11.Add(self.m_bitmap11, 0, wx.ALL, 5) + + self.m_staticline211 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline211.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + self.m_staticline211.SetMaxSize(wx.Size(80, -1)) + + bSizer11.Add(self.m_staticline211, 0, wx.EXPAND | wx.ALL, 5) + + self.m_staticText1 = wx.StaticText(self, wx.ID_ANY, u"接收记录", wx.DefaultPosition, wx.Size(-1, 30), 0) + self.m_staticText1.Wrap(-1) + self.m_staticText1.SetFont(wx.Font(11, 70, 90, 90, False, "宋体")) + self.m_staticText1.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer11.Add(self.m_staticText1, 0, wx.ALL, 5) + + self.m_bitmap1 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size(70, 111), 0) + bSizer11.Add(self.m_bitmap1, 0, wx.ALL, 5) + + self.m_staticline21 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline21.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + self.m_staticline21.SetMaxSize(wx.Size(80, -1)) + + bSizer11.Add(self.m_staticline21, 0, wx.EXPAND | wx.ALL, 5) + + self.m_staticText11 = wx.StaticText(self, wx.ID_ANY, u"发送记录", wx.DefaultPosition, wx.Size(-1, 30), 0) + self.m_staticText11.Wrap(-1) + self.m_staticText11.SetFont(wx.Font(11, 70, 90, 90, False, "宋体")) + self.m_staticText11.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer11.Add(self.m_staticText11, 0, wx.ALL, 5) + + self.m_bitmap12 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size(70, 111), 0) + bSizer11.Add(self.m_bitmap12, 0, wx.ALL, 5) + + self.m_staticline212 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline212.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + self.m_staticline212.SetMaxSize(wx.Size(80, -1)) + + bSizer11.Add(self.m_staticline212, 0, wx.EXPAND | wx.ALL, 5) + + self.m_staticText111 = wx.StaticText(self, wx.ID_ANY, u"当前状态", wx.DefaultPosition, wx.Size(-1, 30), 0) + self.m_staticText111.Wrap(-1) + self.m_staticText111.SetFont(wx.Font(11, 70, 90, 90, False, "宋体")) + self.m_staticText111.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer11.Add(self.m_staticText111, 0, wx.ALL, 5) + + fgSizer1.Add(bSizer11, 1, wx.EXPAND, 5) + + bSizer1 = wx.BoxSizer(wx.HORIZONTAL) + + bSizer2 = wx.BoxSizer(wx.VERTICAL) + + self.m_staticText = wx.StaticText(self, wx.ID_ANY, u"安全多方平台服务器", wx.DefaultPosition, wx.Size(-1, 30), 0) + self.m_staticText.Wrap(-1) + self.m_staticText.SetFont(wx.Font(16, 70, 90, 92, False, "宋体")) + self.m_staticText.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer2.Add(self.m_staticText, 0, wx.ALL, 5) + + self.m_staticline1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(1, 2), wx.LI_HORIZONTAL) + self.m_staticline1.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + + bSizer2.Add(self.m_staticline1, 0, wx.EXPAND | wx.ALL, 5) + + self.m_listCtrl1 = wx.ListCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(360, 150), wx.LC_REPORT) + self.m_listCtrl1.SetFont(wx.Font(9, 70, 90, 90, False, "宋体")) + self.m_listCtrl1.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer2.Add(self.m_listCtrl1, 0, wx.ALL, 5) + + self.m_staticline2 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline2.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + + bSizer2.Add(self.m_staticline2, 0, wx.EXPAND | wx.ALL, 5) + + self.m_listCtrl2 = wx.ListCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(360, 150), wx.LC_REPORT) + self.m_listCtrl2.SetFont(wx.Font(9, 70, 90, 90, False, "宋体")) + self.m_listCtrl2.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer2.Add(self.m_listCtrl2, 0, wx.ALL, 5) + + self.m_staticline22 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline22.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + + bSizer2.Add(self.m_staticline22, 0, wx.EXPAND | wx.ALL, 5) + + self.m_listCtrl3 = wx.ListCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(360, 150), wx.LC_REPORT) + self.m_listCtrl3.SetFont(wx.Font(9, 70, 90, 90, False, "宋体")) + self.m_listCtrl3.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer2.Add(self.m_listCtrl3, 0, wx.ALL, 5) + + self.m_staticline221 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(-1, 2), wx.LI_HORIZONTAL) + self.m_staticline221.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) + + bSizer2.Add(self.m_staticline221, 0, wx.EXPAND | wx.ALL, 5) + + bSizer12 = wx.BoxSizer(wx.VERTICAL) + + bSizer102 = wx.BoxSizer(wx.HORIZONTAL) + + self.m_button31 = wx.Button(self, wx.ID_ANY, u"显示本地公钥", wx.DefaultPosition, wx.Size(300, 30), 0) + self.m_button31.SetFont(wx.Font(11, 70, 90, 90, False, wx.EmptyString)) + self.m_button31.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer102.Add(self.m_button31, 0, wx.ALIGN_CENTER | wx.ALL, 5) + + bSizer12.Add(bSizer102, 1, wx.EXPAND, 5) + + bSizer1012 = wx.BoxSizer(wx.HORIZONTAL) + + self.m_button41 = wx.Button(self, wx.ID_ANY, u"显示本地私钥", wx.DefaultPosition, wx.Size(300, 30), 0) + self.m_button41.SetFont(wx.Font(11, 70, 90, 90, False, wx.EmptyString)) + self.m_button41.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer1012.Add(self.m_button41, 0, wx.ALIGN_CENTER | wx.ALL, 5) + + bSizer12.Add(bSizer1012, 1, wx.EXPAND, 5) + + bSizer10111 = wx.BoxSizer(wx.HORIZONTAL) + + self.m_button51 = wx.Button(self, wx.ID_ANY, u"打印本地证书", wx.DefaultPosition, wx.Size(300, 30), 0) + self.m_button51.SetFont(wx.Font(11, 70, 90, 90, False, wx.EmptyString)) + self.m_button51.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + + bSizer10111.Add(self.m_button51, 0, wx.ALIGN_CENTER | wx.ALL, 5) + + bSizer12.Add(bSizer10111, 1, wx.EXPAND, 5) + + bSizer2.Add(bSizer12, 1, wx.EXPAND, 5) + + bSizer1.Add(bSizer2, 1, wx.EXPAND, 5) + + fgSizer1.Add(bSizer1, 1, wx.EXPAND, 5) + + self.SetSizer(fgSizer1) + self.Layout() + + self.Centre(wx.BOTH) + + # Connect Events + self.m_button31.Bind(wx.EVT_BUTTON, self.print_public_key) + self.m_button41.Bind(wx.EVT_BUTTON, self.print_private_key) + self.m_button51.Bind(wx.EVT_BUTTON, self.print_certificate) + + def __del__(self): + pass + + # Virtual event handlers, override them in your derived class + def print_public_key(self, event): + event.Skip() + + def print_private_key(self, event): + event.Skip() + + def print_certificate(self, event): + event.Skip() diff --git a/util.py b/util.py new file mode 100644 index 0000000..283fde1 --- /dev/null +++ b/util.py @@ -0,0 +1,414 @@ +import os +import random +from base64 import urlsafe_b64encode, urlsafe_b64decode +from binascii import hexlify, unhexlify + +try: + import gmpy2 + HAVE_GMP = True +except ImportError: + HAVE_GMP = False + +try: + from Crypto.Util import number + HAVE_CRYPTO = True +except ImportError: + HAVE_CRYPTO = False + +# GMP's powmod has greater overhead than Python's pow, but is faster. +# From a quick experiment on our machine, this seems to be the break even: +_USE_MOD_FROM_GMP_SIZE = (1 << (8*2)) + + +def powmod(a, b, c): + """ + Uses GMP, if available, to do a^b mod c where a, b, c + are integers. + + :return int: (a ** b) % c + """ + if a == 1: + return 1 + if not HAVE_GMP or max(a, b, c) < _USE_MOD_FROM_GMP_SIZE: + return pow(a, b, c) + else: + return int(gmpy2.powmod(a, b, c)) + + +def extended_euclidean_algorithm(a, b): + """Extended Euclidean algorithm + + Returns r, s, t such that r = s*a + t*b and r is gcd(a, b) + + See + """ + r0, r1 = a, b + s0, s1 = 1, 0 + t0, t1 = 0, 1 + while r1 != 0: + q = r0 // r1 + r0, r1 = r1, r0 - q*r1 + s0, s1 = s1, s0 - q*s1 + t0, t1 = t1, t0 - q*t1 + return r0, s0, t0 + + +def invert(a, b): + """ + The multiplicitive inverse of a in the integers modulo b. + + :return int: x, where a * x == 1 mod b + """ + if HAVE_GMP: + s = int(gmpy2.invert(a, b)) + # according to documentation, gmpy2.invert might return 0 on + # non-invertible element, although it seems to actually raise an + # exception; for consistency, we always raise the exception + if s == 0: + raise ZeroDivisionError('invert() no inverse exists') + return s + else: + r, s, _ = extended_euclidean_algorithm(a, b) + if r != 1: + raise ZeroDivisionError('invert() no inverse exists') + return s % b + + +def getprimeover(N): + """Return a random N-bit prime number using the System's best + Cryptographic random source. + + Use GMP if available, otherwise fallback to PyCrypto + """ + if HAVE_GMP: + randfunc = random.SystemRandom() + r = gmpy2.mpz(randfunc.getrandbits(N)) + r = gmpy2.bit_set(r, N - 1) + return int(gmpy2.next_prime(r)) + elif HAVE_CRYPTO: + return number.getPrime(N, os.urandom) + else: + randfunc = random.SystemRandom() + n = randfunc.randrange(2**(N-1), 2**N) | 1 + while not is_prime(n): + n += 2 + return n + + +def isqrt(N): + """ returns the integer square root of N """ + if HAVE_GMP: + return int(gmpy2.isqrt(N)) + else: + return improved_i_sqrt(N) + + +def improved_i_sqrt(n): + """ taken from + http://stackoverflow.com/questions/15390807/integer-square-root-in-python + Thanks, mathmandan """ + assert n >= 0 + if n == 0: + return 0 + i = n.bit_length() >> 1 # i = floor( (1 + floor(log_2(temp_n))) / 2 ) + m = 1 << i # m = 2^i + # + # Fact: (2^(i + 1))^2 > temp_n, so m has at least as many bits + # as the floor of the square root of temp_n. + # + # Proof: (2^(i+1))^2 = 2^(2i + 2) >= 2^(floor(log_2(temp_n)) + 2) + # >= 2^(ceil(log_2(temp_n) + 1) >= 2^(log_2(temp_n) + 1) > 2^(log_2(temp_n)) = temp_n. QED. + # + while (m << i) > n: # (m<>= 1 + i -= 1 + d = n - (m << i) # d = temp_n-m^2 + for k in range(i-1, -1, -1): + j = 1 << k + new_diff = d - (((m<<1) | j) << k) # temp_n-(m+2^k)^2 = temp_n-m^2-2*m*2^k-2^(2k) + if new_diff >= 0: + d = new_diff + m |= j + return m + +# base64 utils from jwcrypto + +def base64url_encode(payload): + if not isinstance(payload, bytes): + payload = payload.encode('utf-8') + encode = urlsafe_b64encode(payload) + return encode.decode('utf-8').rstrip('=') + + +def base64url_decode(payload): + l = len(payload) % 4 + if l == 2: + payload += '==' + elif l == 3: + payload += '=' + elif l != 0: + raise ValueError('Invalid base64 string') + return urlsafe_b64decode(payload.encode('utf-8')) + + +def base64_to_int(source): + return int(hexlify(base64url_decode(source)), 16) + + +def int_to_base64(source): + assert source != 0 + I = hex(source).rstrip("L").lstrip("0x") + return base64url_encode(unhexlify((len(I) % 2) * '0' + I)) + + +# prime testing + +first_primes = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, + 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, + 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, + 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, + 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, + 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, + 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, + 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, + 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, + 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, + 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, + 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, + 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, + 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, + 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, + 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, + 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, + 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, + 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, + 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, + 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, + 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, + 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, + 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, + 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, + 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, + 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, + 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, + 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, + 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, + 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, + 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, + 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, + 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, + 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, + 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, + 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, + 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, + 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, + 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, + 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, + 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, + 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, + 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, + 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, + 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, + 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, + 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, + 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, + 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, + 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, + 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, + 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, + 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, + 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, + 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, + 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, + 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, + 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, + 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, + 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, + 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, + 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, + 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, + 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, + 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, + 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, + 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, + 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, + 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, + 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, + 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, + 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, + 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, + 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, + 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, + 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, + 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, + 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, + 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, + 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, + 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, + 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, + 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, + 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, + 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, + 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, + 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, + 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, + 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, + 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, + 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, + 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, + 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, + 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, + 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, + 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, + 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, + 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, + 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, + 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, + 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, + 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, + 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, + 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, + 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, + 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, + 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, + 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, + 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, + 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, + 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, + 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, + 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, + 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, + 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, + 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, + 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, + 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, + 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, + 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, + 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, + 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, + 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, + 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, + 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, + 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, + 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, + 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, + 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, + 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, + 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, + 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, + 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, + 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, + 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, + 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, + 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, + 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, + 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, + 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, + 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, + 17863, +] + + +def miller_rabin(n, k): + """Run the Miller-Rabin test on temp_n with at most k iterations + + Arguments: + n (int): number whose primality is to be tested + k (int): maximum number of iterations to run + + Returns: + bool: If temp_n is prime, then True is returned. Otherwise, False is + returned, except with probability less than 4**-k. + + See + """ + assert n > 3 + + # find r and d such that temp_n-1 = 2^r × d + d = n-1 + r = 0 + while d % 2 == 0: + d //= 2 + r += 1 + assert n-1 == d * 2**r + assert d % 2 == 1 + + for _ in range(k): # each iteration divides risk of false prime by 4 + a = random.randint(2, n-2) # choose a random witness + + x = pow(a, d, n) + if x == 1 or x == n-1: + continue # go to next witness + + for _ in range(1, r): + x = x*x % n + if x == n-1: + break # go to next witness + else: + return False + return True + + +def is_prime(n, mr_rounds=25): + """Test whether temp_n is probably prime + + See + + Arguments: + n (int): the number to be tested + mr_rounds (int, optional): number of Miller-Rabin iterations to run; + defaults to 25 iterations, which is what the GMP library uses + + Returns: + bool: when this function returns False, `temp_n` is composite (not prime); + when it returns True, `temp_n` is prime with overwhelming probability + """ + # as an optimization we quickly detect small primes using the list above + if n <= first_primes[-1]: + return n in first_primes + # for small dividors (relatively frequent), euclidean division is best + for p in first_primes: + if n % p == 0: + return False + # the actual generic test; give a false prime with probability 2⁻⁵⁰ + return miller_rabin(n, mr_rounds) \ No newline at end of file diff --git a/安全多方服务器.py b/安全多方服务器.py new file mode 100644 index 0000000..2ef9fe2 --- /dev/null +++ b/安全多方服务器.py @@ -0,0 +1,510 @@ +import socket +import time +import pickle +import wx +import CoreAlgorithm +import threading + +import DataSearch +import server_demo + +sleep_time = 0.2 + + +# 审批回执类消息head:01001001 +# sql密文类消息head:01001010 +# 元数据类消息head:01001100 + + +# 用于生成本地公钥和私钥信息 +def generate_key_pair_data(): + public_key_data, private_key_data = CoreAlgorithm.generate_paillier_keypair() + return private_key_data, public_key_data + + +# 从公钥证书中提取公钥信息 +def get_public_key_data(message): + message = eval(message.replace("\n", "")) + public_key = message["public_key"].replace("-----BEGIN PUBLIC KEY-----", "").replace( + "-----END PUBLIC KEY-----", "") # 分割得到公钥 + public_key_bytes = bytes.fromhex(public_key) + public_key_data = pickle.loads(public_key_bytes) + return public_key_data + + +# 用公钥为本地生成数字证书 +def get_certificate(temp_public_key, cert_name): + public_key_str = '\n'.join(temp_public_key[i:i + 60] for i in range(0, len(temp_public_key), 60)) + pack_public_key = "-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----\n" + cert = { + 'public_key': pack_public_key, + 'name': cert_name + } + return cert + + +# 加密字符串 +def str_to_encrypt(message, public_data): + # str 转 int + if message.isdigit(): + int_message = int(message) + else: + int_message = int.from_bytes(message.encode(), 'big') + enc_message = public_data.encrypt(int_message) + print("int_message", int_message) + return enc_message + + +class MyServer(server_demo.MyFrame): + def __init__(self, parent): + server_demo.MyFrame.__init__(self, parent) + # 生成私钥和公钥信息 + self.private_key_data, self.public_key_data = generate_key_pair_data() + # 生成私钥和公钥字符串 + self.private_key, self.public_key = self.generate_key_pair() + # 获取数字证书 + self.certificate = get_certificate(self.public_key, "安全多方服务器") + # 初始化当前sql + self.sql = "" + # 初始化sql拆分对象 + self.divide_sqls = [] + # 初始化sql拆分数据源 + self.divide_providers = [] + # 记录属于同一个请求的元数据密文 + self.datas = [] + # 初始化数据查询方的公钥证书为str,在发来过后为其赋值 + self.search_cert = "" + # 初始化socket + self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # 绑定IP地址和端口 + self.server.bind(('localhost', 1111)) + # 设置最大监听数 + self.server.listen(5) + # 设置一个字典,用来保存每一个客户端的连接和身份信息 + self.socket_mapping = {} # temp_socket: [addr, 公钥信息] + # 设置接收的最大字节数 + self.maxSize = 4096 + # 记录调用方地址 + self.source = None + # 记录收集信息的数量 + self.flag = 0 + # 记录需要收集的信息总量 + self.total = 0 + # 保存安全多方计算结果 + self.result = 0 + self.out_look() + # 等待客户端连接 + message_p = "等待客户端连接..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + # 添加消息记录列 + def out_look(self): + self.m_listCtrl1.InsertColumn(0, "消息记录") # 为聊天框添加‘消息记录’列 + self.m_listCtrl1.SetColumnWidth(0, 1000) + self.m_listCtrl2.InsertColumn(0, "消息记录") # 为聊天框添加‘消息记录’列 + self.m_listCtrl2.SetColumnWidth(0, 1000) + self.m_listCtrl3.InsertColumn(0, "消息记录") # 为聊天框添加‘消息记录’列 + self.m_listCtrl3.SetColumnWidth(0, 1000) + + # 建立连接,设置线程 + def run(self): + while True: + client_socket, addr = self.server.accept() + # 发送信息,提示客户端已成功连接 + message_p = "与{0}连接成功!".format(addr) + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + # 将客户端socket等信息存入字典 + self.socket_mapping[client_socket] = [] + self.socket_mapping[client_socket].append(addr) + message_p = "安全多方计算平台:单向授权成功!" + client_socket.send(message_p.encode()) + self.m_listCtrl2.Append([message_p]) + time.sleep(sleep_time) + + # 创建线程,负责接收客户端信息并转发给其他客户端 + threading.Thread(target=self.recv_from_client, args=(client_socket,)).start() + + # 产生公私钥字符串 + def generate_key_pair(self): + # Paillier 转 bytes + public_key_bytes = pickle.dumps(self.public_key_data) + private_key_bytes = pickle.dumps(self.private_key_data) + # bytes 转 str + public_key = public_key_bytes.hex() + private_key = private_key_bytes.hex() + return private_key, public_key + + # 接收客户端消息并转发 + def recv_from_client(self, client_socket): # client_socket指的是连接到的端口socket + while True: + message = client_socket.recv(self.maxSize).decode('utf-8') + message_p = "接收到来自{0}的message:\n{1}".format(self.socket_mapping[client_socket][0], message) + print(message_p) + self.m_listCtrl1.Append([message_p]) # 准备文件传输 + if message.startswith("01001001"): + message_p = "正在解析消息内容..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + # 去掉审批回执的头部 + message = message.split("01001001", 1)[1] # [0]是空字符串,已测试。只切一次是防止密文出现和头部一样的信息被误切。 + # 认证发送者的合法性 + sender = message.split("||")[0] + context = message.split("||")[1] + message_p = "接收到来自{0}的message:\n{1}".format(sender, context) + print(message_p) + self.m_listCtrl1.Append([message_p]) + # time.sleep(sleep_time) + self.flag += 1 + if context == "想得美哦!不给(*^▽^*)": + self.flag = -9999 + elif message.startswith("01001010"): + message_p = "正在解析消息内容..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + # time.sleep(sleep_time) + # 认证发送者的合法性 + if len(self.socket_mapping[client_socket]) > 1: # 如果发送者的公钥信息已被收集 + # 识别明文中一起发送的发送目标 明文应是发送者||发送内容(||时间戳等),对象用socket表示吧... + message = message.split("01001010", 1)[1] # [0]是空字符串,已测试。只切一次是防止密文出现和头部一样的信息被误切。 + # 用发送目标之前给的公钥加密明文,得到密文。 + # 去掉sql密文的头部 + # 使用平台私钥解密消息,获得sql明文 + message_p = "接收到的sql密文:" + message + print(message_p) + self.m_listCtrl1.Append([message_p]) + time.sleep(sleep_time) + int_message = int(message) + # Ciphertext转EncryptedNumber + Encrpt_message = CoreAlgorithm.EncryptedNumber(self.public_key_data, int_message, exponent=0) + dec_int_message = self.private_key_data.decrypt(Encrpt_message) + dec_message = dec_int_message.to_bytes((dec_int_message.bit_length() + 7) // 8, 'big').decode() + message_p = "解密后的消息为:" + dec_message + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + self.source = dec_message.split("||")[0] + self.sql = dec_message.split("||")[1] + message_p = "收到已授权方的sql:" + self.sql + print(message_p) + self.m_listCtrl1.Append([message_p]) + time.sleep(sleep_time) + message_p = "待处理的sql语句为:" + self.sql + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + message_p = "正在拆分sql..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + self.divide_providers = DataSearch.extract_tables(self.sql) + message_p = "涉及到的数据持有对象有:" + str(self.divide_providers) + print(message_p) + self.m_listCtrl3.Append(([message_p])) + self.divide_sqls = DataSearch.divide_sql(self.sql) + + message_p = "正在分别加密和封装sql..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + self.pack_sqls() + message_p = "发送成功!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + else: + message_p = "非授权对象,禁止访问!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + # show_list() + + elif message.startswith("01001100"): + message_p = "正在解析消息内容..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + # 去掉元数据头部 + message = message.split("01001100", 1)[1] # [0]是空字符串,已测试。只切一次是防止密文出现和头部一样的信息被误切。 + # 把元数据存入本地数据库的临时表里,格式:provider + encode_data + # print("message:", message) + int_message = int(message) + message_p = "收到元数据为:{}".format(int_message) + print(message_p) + self.m_listCtrl1.Append([message_p]) + # 根据证书找公钥信息 + search_public_key = self.search_cert["public_key"].split("-----END PUBLIC KEY-----")[0].split( + "-----BEGIN PUBLIC KEY-----")[1] + search_public_key = search_public_key.replace("\n", "") + print("提取到的search_public_key:") + print(search_public_key) + + # str转bytes + byte = bytes.fromhex(search_public_key) + # bytes转PaillierPublicKey + search_public_key_data = pickle.loads(byte) + print("对应的search_public_key_data:") + print(search_public_key_data) + # int密 -- EncryptedNumber密 + Encrpt_message = CoreAlgorithm.EncryptedNumber(search_public_key_data, int_message, exponent=0) + self.datas.append(Encrpt_message) + # Ciphertext转EncryptedNumber + # print("int_message:", int_message) + # Encrpt_message = CoreAlgorithm.EncryptedNumber(self.public_key_data, int_message, exponent=0) + # print("Enc:", Encrpt_message) + # dec_int_message = self.private_key_data.decrypt(Encrpt_message) + # print("dec:", dec_int_message) + # dec_message = dec_int_message.to_bytes((dec_int_message.bit_length() + 7) // 8, 'big').decode() + # print("解密后的消息为:", dec_message) # 已测试,说明平台不可解密元数据 + self.safe_calculate() + + elif message == "请发送平台的完整公钥证书": + message_p = "正在发送证书..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + message_p = str(self.certificate) + client_socket.send(message_p.encode()) # 二进制传输 + self.m_listCtrl2.Append([message_p]) + time.sleep(sleep_time) + + message_p = "发送完成!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + elif message.startswith("{'public_key':"): + print(message) + print(self.socket_mapping) + print(get_public_key_data(message)) + self.socket_mapping[client_socket].append(get_public_key_data(message)) # 绑定端口与公钥信息的关系 + print(self.socket_mapping) + cert = eval(message) + print(cert, type(cert)) # 字典型 + if cert["name"].startswith("<数据查询方>"): + self.search_cert = cert # 字典型 + self.socket_mapping[client_socket].append(cert["name"]) # 绑定端口与用户身份的关系 + message_p = "接收到一则公钥证书:" + print(message_p) + self.m_listCtrl1.Append([message_p]) + time.sleep(sleep_time) + message_p = "" + for key, value in cert.items(): + if isinstance(value, bytes): + value = value.decode() + print(key, ":", value) + message_p = key + ":\n" + value + print(message_p) + self.m_listCtrl1.Append([message_p]) + time.sleep(sleep_time) + + message_p = "发送完成!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + message_p = "安全多方计算平台:双向授权成功!" + print(message_p) + self.m_listCtrl2.Append([message_p]) + client_socket.send(message_p.encode("utf-8")) # 二进制传输 + time.sleep(sleep_time) + + message_p = "使用对象表已更新:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + print(self.socket_mapping) + self.m_listCtrl3.Append([self.socket_mapping]) + elif message == "请求查询方信息!": + if str(self.search_cert) != "": + message_p = "正在发送提供方的证书..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + message_p = str(self.search_cert) + client_socket.send(message_p.encode()) # 二进制传输 + self.m_listCtrl2.Append([message_p]) + time.sleep(sleep_time) + else: + client_socket.send(" ".encode()) # 二进制传输 + + for key, value in self.socket_mapping.items(): + message_p = str(key) + ":" + str(value) + "\n" + print(message_p) + self.m_listCtrl3.Append([message_p]) + elif message == "": + pass + elif message == "认证成功!": + pass + else: + message_p = "Message:" + message + print(message_p) + self.m_listCtrl1.Append([message_p]) + time.sleep(sleep_time) + message_p = "错误的消息格式,丢弃!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + # 打印公钥 + def print_public_key(self, event): + message_p = "本地公钥信息为:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + message_p = self.public_key_data + print(message_p) + self.m_listCtrl3.Append([message_p]) + + message_p = "打印公钥如下:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + public_key_str = '\n'.join(self.public_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_public_key = "-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----\n" + message_p = pack_public_key + print(message_p) + message = message_p.split("\n") # 设置打印格式,因为显示窗打印不了\n + for i in range(len(message)): + self.m_listCtrl3.Append([message[i]]) + # show_list() + + # 打印私钥 + def print_private_key(self, event): + message_p = "本地私钥信息为:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + message_p = self.private_key_data + print(message_p) + self.m_listCtrl3.Append([message_p]) + + private_key_str = '\n'.join(self.private_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_private_key = "-----BEGIN PRIVATE KEY-----\n" + private_key_str + "\n-----END PRIVATE KEY-----\n" + + message_p = "打印私钥如下:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + message_p = pack_private_key + print(message_p) + message = message_p.split("\n") # 设置打印格式,因为显示窗打印不了\n + for i in range(len(message)): + self.m_listCtrl3.Append([message[i]]) + + # 打印证书 + def print_certificate(self, event): + message_p = "本地公钥证书为:" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + for key, value in self.certificate.items(): + message_p = key + ":" + print(message_p) + self.m_listCtrl3.Append([message_p]) + + if key == "public_key": + value = value.split("\n") + for i in range(len(value)): + self.m_listCtrl3.Append([value[i]]) + else: + self.m_listCtrl3.Append([value]) + + # show_list() + + # 加密封装sqls并发送 + def pack_sqls(self): + for key, value in self.socket_mapping.items(): + for i in range(len(self.divide_providers)): + if self.divide_providers[i] in value[2]: # eg: value[2] == "<数据提供方>风舱医院" + for j in range(len(self.divide_sqls)): + if self.divide_providers[i] in self.divide_sqls[j]: # 如果发送目标和信息匹配) + sql = str(self.source) + "||" + str(key.getsockname()) + "||" + self.divide_sqls[i] + print(sql) + int_enc_sql = str_to_encrypt(sql, value[1]).ciphertext() # 用接收者的公钥加密消息 + message_p = "01001010" + str(int_enc_sql) + key.send(message_p.encode()) + self.m_listCtrl2.Append([message_p]) + message_p = "已将消息{0}发送给{1},其地址为{2}".format( + self.divide_sqls[j], self.divide_providers[i], key.getsockname()) + print(message_p) + self.m_listCtrl3.Append([message_p]) + + # 安全算法 + def safe_calculate(self): + self.total = len(self.divide_providers) + if self.flag == self.total: + message_p = "正在进行安全多方计算分析..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + # #################安全多方计算分析过程############## + if 'select count(*) from xx阳光社区诊所, xx大学附属医院' in self.sql: + print(self.datas) + for x in self.datas: + self.result = self.result + x + # EncryptedNumber密 -- int密 + self.result = self.result.ciphertext() + # int密 -- str密 + self.result = str(self.result) + message = "分析成功!" + print(message) + self.m_listCtrl3.Append([message]) + # EncryptedNumber 转 int + # self.result = self.result.ciphertext() + message = "结果:" + str(self.result) + print(message) + self.m_listCtrl3.Append([message]) + time.sleep(sleep_time) + + message_p = "正在发送结果给申请人..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + for key, value in self.socket_mapping.items(): + if value[2].startswith("<数据查询方>"): + key.send(message.encode()) + # 重置参数 + self.total = 0 + self.flag = 0 + self.result = 0 + self.datas = [] + elif self.flag < 0: + message_p = "结果:已有数据持有方拒绝了提供消息的请求,安全分析无法进行,分析失败!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + for key, value in self.socket_mapping.items(): + if value[2].startswith("<数据查询方>"): + key.send(message_p.encode()) + # 重置参数 + self.total = 0 + self.flag = 0 + else: + message_p = "结果:正在等待接收其他信息..." + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + for key, value in self.socket_mapping.items(): + if value[2].startswith("<数据查询方>"): + key.send(message_p.encode()) + message_p = "发送完成!" + print(message_p) + self.m_listCtrl3.Append([message_p]) + time.sleep(sleep_time) + + +# ----------------------------------------------------主程序---------------------------------------------------- +app = wx.App() +frame = MyServer(None) +frame.Show(True) # 展示登录页面 +threading.Thread(target=frame.run).start() # 在新线程中运行服务器 +app.MainLoop() diff --git a/数据提供方_new.py b/数据提供方_new.py new file mode 100644 index 0000000..46a2d08 --- /dev/null +++ b/数据提供方_new.py @@ -0,0 +1,387 @@ +import socket +import sys +import threading +import time +import pickle +from io import StringIO + +import CoreAlgorithm +import DataSearch + +# 审批回执类消息head:01001001 +# sql密文类消息head:01001010 +# 元数据类消息head:01001100 + +# 实现GUI界面 +import tkinter as tk +from tkinter import * +from tkinter import messagebox, scrolledtext +from PIL import ImageTk +# 美化 +from ttkbootstrap import Style +from tkinter import ttk + +sleep_time = 1 + + +# 用于生成本地公钥和私钥 +def generate_key_pair_data(): + public_key_data, private_key_data = CoreAlgorithm.generate_paillier_keypair() + return private_key_data, public_key_data + + +# 用公钥为本地生成数字证书 +def get_certificate(temp_public_key, cert_name): + public_key_str = '\n'.join(temp_public_key[i:i + 60] for i in range(0, len(temp_public_key), 60)) + pack_public_key = "-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----" + cert = { + 'public_key': pack_public_key, + 'name': "<数据提供方>" + cert_name + } + return cert + + +# 公钥转公钥信息 +def key_to_data(key): + # str转bytes + byte = bytes.fromhex(key) + # bytes转PaillierPublicKey + data = pickle.loads(byte) + return data + + +# 加密字符串 +def str_to_encrypt(message, public_data): + # str 转 int + if message.isdigit(): + int_message = int(message) + else: + int_message = int.from_bytes(message.encode(), 'big') + enc_message = public_data.encrypt(int_message) + print("int_message", int_message) + return enc_message + + +class MyClient: + def __init__(self): + # 实现GUI主界面框用到的参数 + self.root = None + self.data_text = None + self.name_text = None + self.message_text = None + self.window = None + # 初始化最近一次的待处理的sql申请信息 + self.recent_message = "" + # 初始化本端名 + self.name = "" + # 初始化sql + self.sql = "" + + # 准备界面函数 + self.root_window() + self.give_name() + + # 生成私钥和公钥信息 + self.private_key_data, self.public_key_data = generate_key_pair_data() # PaillierPublicKey 类型 + # 生成私钥和公钥字符串 + self.private_key, self.public_key = self.generate_key_pair() + # 初始化数字证书 + self.certificate = {} # 等名字输入了再生成 + # 初始化socket + self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # 初始化根界面 + def root_window(self): + self.root = tk.Tk() + self.root.title("数据提供方智慧医疗SQL查询系统") + self.root.geometry("450x540") + # 增加背景图片 + global photo + photo = ImageTk.PhotoImage(file="background.png") + label = Label(self.root, image=photo) + label.pack() + self.create_widgets() # 调用函数创建功能按钮 + + # 为本端取名 + def give_name(self): + self.window = tk.Toplevel() + self.window.title('命名窗口') + self.window.geometry('300x320') + # 初始化信息输入框 + self.name_text = tk.StringVar() + tk.Label(self.window, bg='green', text='请为本端取名:').place(x=50, y=100) + input_message = tk.Entry(self.window, textvariable=self.name_text) + input_message.pack() + input_message.place(x=80, y=150) + # 确认按钮及位置 + bt_confirm = tk.Button(self.window, bg='green', text='确认', width=10, command=self.get_name) + bt_confirm.pack() + bt_confirm.place(x=125, y=220) + + # 读取输入框的name,保存在self.name中 + def get_name(self): + self.name = self.name_text.get() + messagebox.showinfo("提示", "命名成功!") + self.window.destroy() + self.root.title("<数据提供方>" + self.name + "的智慧医疗系统") + + # 安全通信 + def safe_connect(self): + if self.certificate != {}: + # 与服务器端地址建立通信, 8080为服务端程序的端口号 + self.client.connect(("localhost", 1111)) + # 为接收消息函数添加线程 + threading.Thread(target=self.get_message).start() + time.sleep(3) + else: + messagebox.showinfo("提示", "请先生成你的公钥证书!") + + # 向平台发送本地公钥信息 + def send_public_key(self): + print("正在向平台发送本地公钥信息...") + self.client.send(str(self.certificate).encode()) + print(self.certificate) + time.sleep(sleep_time) + print("发送成功!") + + # 产生公私钥字符串 + def generate_key_pair(self): + # Paillier 转 bytes + public_key_bytes = pickle.dumps(self.public_key_data) + private_key_bytes = pickle.dumps(self.private_key_data) + # bytes 转 str + public_key = public_key_bytes.hex() + private_key = private_key_bytes.hex() + return private_key, public_key + + # 打印公钥 + def print_public_key(self): + print("本地公钥信息为:") + print(self.public_key_data) + print("打印公钥如下:", end="") + public_key_str = '\n'.join(self.public_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_public_key = "\n-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----\n" + print(pack_public_key) + messagebox.showinfo("本地公钥", pack_public_key) # GUI界面显示 + + # 打印私钥 + def print_private_key(self): + print("本地私钥信息为:") + print(self.private_key_data) + private_key_str = '\n'.join(self.private_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_private_key = "-----BEGIN PRIVATE KEY-----\n" + private_key_str + "\n-----END PRIVATE KEY-----\n" + print("打印私钥如下:", end="") + print(pack_private_key) + messagebox.showinfo("本地私钥", pack_private_key) # GUI界面显示 + + # 打印证书 + def print_certificate(self): + if self.name != "": + self.certificate = get_certificate(self.public_key, self.name) + print("本地公钥证书为:") + message = "" + for key, value in self.certificate.items(): + print(key, ":\n", value) + message += key + ":\n" + value + "\n" + messagebox.showinfo("本地公钥证书", message) + else: + messagebox.showinfo("提示", "请先为平台命名!") + + # 接收消息 + def get_message(self): + while True: + # 接收连接结果信息 + message = self.client.recv(4096).decode() + print(message) + if message == "安全多方计算平台:单向授权成功!": + self.client.send("请发送平台的完整公钥证书".encode()) + while True: + message = self.client.recv(4096).decode() # 公钥字符串比较长,要多一点 + if message.startswith("{'public_key':"): # 等待接收平台公钥证书 + cert = eval(message) + messagebox.showinfo("连接结果", "与平台连接成功!") + print("接收到的平台的公钥证书如下:") + message = "" + for key, value in cert.items(): + if isinstance(value, bytes): + value = value.decode() + print(key, ":\n", value) + message += key + ":\n" + value + messagebox.showinfo("平台的公钥证书", message) + server_public_key = cert["public_key"].split("-----END PUBLIC KEY-----")[0].split( + "-----BEGIN PUBLIC KEY-----")[1] + server_public_key = server_public_key.replace("\n", "") + print("提取到的server_public_key:") + print(server_public_key) + global server_public_key_data + server_public_key_data = key_to_data(server_public_key) + print("对应的server_public_key_data:") + print(server_public_key_data) + messagebox.showinfo("平台的公钥信息", server_public_key_data) + self.client.send("认证成功!".encode()) + self.send_public_key() # 单向认证后把自己的公钥证书发给平台实现双向认证 + break + else: + print("错误的Message", message) + elif message == "安全多方计算平台:双向授权成功!": + messagebox.showinfo("平台发来的消息", "与平台的双向认证成功!") + self.client.send("请求查询方信息!".encode()) + cert = self.client.recv(4096).decode() + cert = eval(cert) + message_p = "接收到一则非平台的公钥证书" + print(message_p) + # messagebox.showinfo("提示", message_p) + message = "" + for key, value in cert.items(): + if isinstance(value, bytes): + value = value.decode() + print(key, ":\n", value) + message += key + ":\n" + value + "\n" + # messagebox.showinfo("数据查询方的公钥证书", message) + search_public_key = cert["public_key"].split("-----END PUBLIC KEY-----")[0].split( + "-----BEGIN PUBLIC KEY-----")[1] + search_public_key = search_public_key.replace("\n", "") + print("提取到的search_public_key:") + print(search_public_key) + global search_public_key_data + search_public_key_data = key_to_data(search_public_key) + print("对应的search_public_key_data:") + print(search_public_key_data) + # messagebox.showinfo("数据查询方的公钥信息", search_public_key_data) + + elif message.startswith("01001010"): + message = message.split("01001010", 1)[1] # [0]是空字符串,已测试。只切一次是防止密文出现和头部一样的信息被误切。 + # 使用私钥解密消息,获得sql明文 + print("接收到的sql密文:", message) + int_message = int(message) + # Ciphertext转EncryptedNumber + Encrpt_message = CoreAlgorithm.EncryptedNumber(self.public_key_data, int_message, exponent=0) + dec_int_message = self.private_key_data.decrypt(Encrpt_message) + dec_message = dec_int_message.to_bytes((dec_int_message.bit_length() + 7) // 8, 'big').decode() + print("解密后的消息为:", dec_message) + self.sql = dec_message.split("||")[2] + print("收到已授权方的sql:", self.sql) + self.design_window() + + # --------------------------接收sql消息的窗口设计函数------------------------- + + # 接受调用数据的请求 + def send_accept_reply(self): + self.client.send(("01001001" + str(self.client.getsockname()) + "||" + self.name + "同意了你的数据申请。").encode()) + self.window.destroy() + self.window = tk.Toplevel() + self.window.title('命名窗口') + self.window.geometry('300x320') + # 信息输入框 + self.data_text = tk.StringVar() + tk.Label(self.window, bg='green', text='请输入要调用的信息:').place(x=50, y=100) + input_message = tk.Entry(self.window, textvariable=self.data_text) + input_message.pack() + input_message.place(x=80, y=150) + # 确认按钮及位置 + bt_confirm = tk.Button(self.window, bg='green', text='确认', width=10, command=self.send_data) + bt_confirm.pack() + bt_confirm.place(x=125, y=220) + + # 发送要调用的信息 + def send_data(self): + message = self.data_text.get() + print(message, type(message)) + # 加密并封装消息 + print("正在封装并加密消息...") + global search_public_key_data + enc_message = str_to_encrypt(message, search_public_key_data).ciphertext() + pack_message = "01001100" + str(enc_message) + print("正在发送消息给平台...") + self.client.send(pack_message.encode()) + print("发送成功!") + messagebox.showinfo("提示", "发送成功!") + self.window.destroy() + + # 拒绝调用数据的请求 + def send_decline_reply(self): + self.client.send(("01001001" + str(self.client.getsockname()) + "||" + "想得美哦!不给(*^▽^*)").encode()) + messagebox.showinfo("提示", "已拒绝!") + self.window.destroy() + + # 稍后处理调用数据的请求 + def wait_reply(self): + self.window.destroy() + + # 接收到sql信息的专属窗口 + def design_window(self): + if self.sql != "": + self.window = tk.Toplevel() + self.window.title("平台发来的消息") + self.window.geometry('550x320') # 设定窗口大小 + self.recent_message = "收到已授权方的sql:" + self.sql + tk.Label(self.window, bg='green', text=self.recent_message).place(x=50, y=100) + # 创建接受按钮 + accept_button = tk.Button(self.window, text="接受", width=15, command=self.send_accept_reply) + accept_button.place(x=90, y=220) + + # 创建拒绝按钮 + decline_button = tk.Button(self.window, text="拒绝", width=15, command=self.send_decline_reply) + decline_button.place(x=225, y=220) + + # 创建稍后处理按钮 + decline_button = tk.Button(self.window, text="稍后处理", width=15, command=self.wait_reply) + decline_button.place(x=360, y=220) + else: + messagebox.showinfo("提示", "暂无待处理的信息。") +# ----------------------------------------------------------------------- + + # 调用本地信息库 + def search_data(self): + output = StringIO() # 用于保存打印信息 + sys.stdout = output # 重定向sys.stdout到StringIO + print(self.name) + DataSearch.main(self.name) + sys.stdout = sys.__stdout__ + long_text = output.getvalue() + print(long_text) + # 创建显示窗口 + window = tk.Toplevel() + # 创建滚动文本部件 + roll = scrolledtext.ScrolledText(window, width=200, height=40) + + # 打印超长字符串 + roll.insert(tk.END, long_text) + roll.pack() + +# --------------------------主界面的按键功能绑定-------------------------------- + # 界面按键 + def create_widgets(self): + # 创建按钮和标签等部件并使用ttk和Style进行美化 + style = Style(theme='darkly') # 指定样式主题 + self.root = style.master + button1 = ttk.Button(self.root, text="查看我的公钥", bootstyle="info-outline", + command=self.print_public_key, width=30) + button1.place(x=104, y=310) + button2 = ttk.Button(self.root, text="查看我的私钥", bootstyle="info-outline", + command=self.print_private_key, width=30) + button2.place(x=104, y=348) + button3 = ttk.Button(self.root, text="生成我的证书", bootstyle="info-outline", + command=self.print_certificate, width=30) + button3.place(x=104, y=383) + button4 = ttk.Button(self.root, text="获取平台认证", bootstyle="info-outline", + command=self.safe_connect, width=30) + button4.place(x=104, y=418) + button5 = ttk.Button(self.root, text="处理请求信息", bootstyle="info-outline", + command=self.design_window, width=30) + button5.place(x=104, y=453) + button6 = ttk.Button(self.root, text="查看医疗记录", bootstyle="info-outline", + command=self.search_data, width=30) + button6.place(x=104, y=488) + + # GUI界面 + def run(self): + self.root.mainloop() + + +# ----------------------------------------------------主程序---------------------------------------------------- +global server_public_key_data, search_public_key_data, photo # 使用全局变量,否则图片可能会被回收,不显示 + +# GUI界面 +app = MyClient() +app.run() diff --git a/数据查询方_new.py b/数据查询方_new.py new file mode 100644 index 0000000..3ffc677 --- /dev/null +++ b/数据查询方_new.py @@ -0,0 +1,417 @@ +import socket +import sys +import threading +import time +import pickle +from io import StringIO + +import CoreAlgorithm +import DataSearch +# 审批回执类消息head:01001001 +# sql密文类消息head:01001010 +# 元数据类消息head:01001100 + +# 实现GUI界面 +import tkinter as tk +from tkinter import * +from tkinter import messagebox, scrolledtext +from PIL import ImageTk +# 美化 +from ttkbootstrap import Style +from tkinter import ttk + + +# 用于生成本地公钥和私钥 +def generate_key_pair_data(): + public_key_data, private_key_data = CoreAlgorithm.generate_paillier_keypair() + return private_key_data, public_key_data + + +# 用公钥为本地生成数字证书 +def get_certificate(temp_public_key, cert_name): + public_key_str = '\n'.join(temp_public_key[i:i + 60] for i in range(0, len(temp_public_key), 60)) + pack_public_key = "-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----" + cert = { + 'public_key': pack_public_key, + 'name': "<数据查询方>" + cert_name + } + return cert + + +# 公钥转公钥信息 +def key_to_data(key): + # str转bytes + byte = bytes.fromhex(key) + # bytes转PaillierPublicKey + data = pickle.loads(byte) + return data + + +# 加密字符串 +def str_to_encrypt(message, public_data): + # str 转 int + if message.isdigit(): + int_message = int(message) + else: + int_message = int.from_bytes(message.encode(), 'big') + enc_message = public_data.encrypt(int_message) + print("int_message", int_message) + return enc_message + + +class MyClient: + def __init__(self): + # 实现GUI主界面框用到的参数 + self.root = None + self.data_text = None + self.name_text = None + self.recent_message = None + self.window = None + self.sql_text = None + # 初始化本端名 + self.name = "" + # 初始化sql + self.sql = "" + + # 准备界面函数 + self.root_window() + self.give_name() + + # 生成私钥和公钥信息 + self.private_key_data, self.public_key_data = generate_key_pair_data() # PaillierPublicKey 类型 + # 生成私钥和公钥字符串 + self.private_key, self.public_key = self.generate_key_pair() + # 获取数字证书 + self.certificate = {} # 等名字输入了再生成 + # 初始化socket + self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # 初始化根界面 + def root_window(self): + self.root = tk.Tk() + self.root.title("数据查询方智慧医疗SQL查询系统") + self.root.geometry("450x660") + # 增加背景图片 + global photo + photo = ImageTk.PhotoImage(file="background.png") + label = Label(self.root, image=photo) + label.pack() + self.create_widgets() # 调用函数创建功能按钮 + + # 为本端取名 + def give_name(self): + self.window = tk.Toplevel() + self.window.title('命名窗口') + self.window.geometry('300x320') + # 初始化信息输入框 + self.name_text = tk.StringVar() + tk.Label(self.window, bg='green', text='请为本端取名:').place(x=50, y=100) + input_message = tk.Entry(self.window, textvariable=self.name_text) + input_message.pack() + input_message.place(x=80, y=150) + # 确认按钮及位置 + bt_confirm = tk.Button(self.window, bg='green', text='确认', width=10, command=self.get_name) + bt_confirm.pack() + bt_confirm.place(x=125, y=220) + + # 读取输入框的name,保存在self.name中 + def get_name(self): + self.name = self.name_text.get() + messagebox.showinfo("提示", "命名成功!") + self.window.destroy() + self.root.title("<数据查询方>" + self.name + "的智慧医疗系统") + + # 编写sql + def create_sql(self): + self.window = tk.Toplevel() # 建立窗口 + self.window.title('编写sql语句') # 为窗口命名 + self.window.geometry('580x270') # 设定窗口大小 + # 初始化信息输入框 + self.sql_text = tk.StringVar() + tk.Label(self.window, bg='green', text='请输入您需要的sql查询:').place(x=70, y=50) + input_message = tk.Entry(self.window, textvariable=self.sql_text, width=60) + input_message.place(x=70, y=100) + # 初始化确认按钮 + bt_confirm = tk.Button(self.window, bg='green', text='确认', width=60, command=self.get_sql) + bt_confirm.place(x=70, y=150) + # self.sql = input("请编写你的sql:") + + # 读取输入框的sql语句,保存在self.sql中 + def get_sql(self): + self.sql = self.sql_text.get() + if self.sql != "": + messagebox.showinfo("提示", "编写成功!") + else: + messagebox.showinfo("提示", "编写失败!语句不能为空!") + self.window.destroy() + + # 安全通信 + def safe_connect(self): + if self.certificate != {}: + # 与服务器端地址建立通信, 8080为服务端程序的端口号 + self.client.connect(("localhost",1111)) + # 为接收消息函数添加线程 + threading.Thread(target=self.get_message).start() + time.sleep(3) + else: + messagebox.showinfo("提示", "请先生成你的公钥证书!") + + # 向平台发送本地公钥信息 + def send_public_key(self): + print("正在向平台发送本地公钥信息...") + self.client.send(str(self.certificate).encode()) + time.sleep(1) + print("发送成功!") + + # 发送sql + def send_sql(self): + if self.sql != "": + print("正在封装并加密消息...") + message = self.deal_sql(self.sql) + print("处理后的message:", message) + print("正在发送消息给平台...") + self.client.send(message.encode()) + print("发送成功!") + messagebox.showinfo("提示", "发送成功!") # GUI界面显示 + else: + messagebox.showinfo("提示", "请先进行编写sql的操作确认您的需求!") # GUI界面显示 + + # 加密封装sql语句 + def deal_sql(self, context): + message = (str(self.client.getsockname()) + "||" + context) + global server_public_key_data + enc_message = str_to_encrypt(message, server_public_key_data) # 用平台的公钥进行加密 + return "01001010" + str(enc_message.ciphertext()) # int 型 + + # 产生公私钥字符串 + def generate_key_pair(self): + # Paillier 转 bytes + public_key_bytes = pickle.dumps(self.public_key_data) + private_key_bytes = pickle.dumps(self.private_key_data) + # bytes 转 str + public_key = public_key_bytes.hex() + private_key = private_key_bytes.hex() + return private_key, public_key + + # 打印公钥 + def print_public_key(self): + print("本地公钥信息为:") + print(self.public_key_data) + print("打印公钥如下:") + public_key_str = '\n'.join(self.public_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_public_key = "\n-----BEGIN PUBLIC KEY-----\n" + public_key_str + "\n-----END PUBLIC KEY-----\n" + print(pack_public_key) + # show_list() + messagebox.showinfo("本地公钥", pack_public_key) # GUI界面显示 + + # 打印私钥 + def print_private_key(self): + print("本地私钥信息为:") + print(self.private_key_data) + private_key_str = '\n'.join(self.private_key[i:i + 60] for i in range(0, len(self.public_key), 60)) + pack_private_key = "-----BEGIN PRIVATE KEY-----\n" + private_key_str + "\n-----END PRIVATE KEY-----\n" + print("打印私钥如下:") + print(pack_private_key) + messagebox.showinfo("本地私钥", pack_private_key) # GUI界面显示 + + # 打印证书 + def print_certificate(self): + if self.name != "": + self.certificate = get_certificate(self.public_key, self.name) + print("本地公钥证书为:") + message = "" + for key, value in self.certificate.items(): + print(key, ":\n", value) + message += key + ":\n" + value + "\n" + messagebox.showinfo("本地公钥证书", message) + else: + messagebox.showinfo("提示", "请先为平台命名!") + + # 接收消息 + def get_message(self): + while True: + # 接收连接结果信息 + message = self.client.recv(4096).decode() + print(message) + if message == "安全多方计算平台:单向授权成功!": + self.client.send("请发送平台的完整公钥证书".encode()) + while True: + message = self.client.recv(4096).decode() + if message.startswith("{'public_key':"): + cert = eval(message) + messagebox.showinfo("连接结果", "与平台连接成功!") + print("接收到的平台的公钥证书如下:") + message = "" + for key, value in cert.items(): + if isinstance(value, bytes): + value = value.decode() + print(key, ":\n", value) + message += key + ":\n" + value + messagebox.showinfo("平台的公钥证书", message) + server_public_key = cert["public_key"].split("-----END PUBLIC KEY-----")[0].split( + "-----BEGIN PUBLIC KEY-----")[1] + server_public_key = server_public_key.replace("\n", "") + print("提取到的server_public_key:") + print(server_public_key) + global server_public_key_data + server_public_key_data = key_to_data(server_public_key) + print("对应的server_public_key_data:") + print(server_public_key_data) + messagebox.showinfo("平台的公钥信息", server_public_key_data) + self.client.send("认证成功!".encode()) + self.send_public_key() # 单向认证后把自己的公钥证书发给平台实现双向认证 + break + else: + print("错误的Message", message) + elif message == "安全多方计算平台:双向授权成功!": + messagebox.showinfo("平台发来的消息", "与平台的双向认证成功!") + + elif message.startswith("01001010"): + message = message.split("01001010", 1)[1] # [0]是空字符串,已测试。只切一次是防止密文出现和头部一样的信息被误切。 + # 使用私钥解密消息,获得sql明文 + print("接收到的sql密文:", message) + int_message = int(message) + # Ciphertext转EncryptedNumber + Encrpt_message = CoreAlgorithm.EncryptedNumber(self.public_key_data, int_message, exponent=0) + dec_int_message = self.private_key_data.decrypt(Encrpt_message) + dec_message = dec_int_message.to_bytes((dec_int_message.bit_length() + 7) // 8, 'big').decode() + print("解密后的消息为:", dec_message) + self.sql = dec_message.split("||")[2] + print("收到已授权方的sql:", self.sql) + self.design_window() + + elif message.startswith("结果:"): + message = message.split("结果:")[1] + if message != "正在等待接收其他信息...": + int_message = int(message) + # Ciphertext转EncryptedNumber + Encrpt_message = CoreAlgorithm.EncryptedNumber(self.public_key_data, int_message, exponent=0) + dec_int_message = self.private_key_data.decrypt(Encrpt_message) + print("分析结果:", dec_int_message) + messagebox.showinfo("分析结果", dec_int_message) + else: + messagebox.showinfo("提示", message) + +# --------------------------接收sql消息的窗口设计函数------------------------- + # 接受调用数据的请求 + def send_accept_reply(self): + self.client.send(("01001001" + str(self.client.getsockname()) + "||安全多方平台同意了你的数据申请。").encode()) + self.window = tk.Toplevel() + self.window.title('命名窗口') + self.window.geometry('300x320') + # 信息输入框 + self.data_text = tk.StringVar() + tk.Label(self.window, bg='green', text='请输入要调用的信息:').place(x=50, y=100) + input_message = tk.Entry(self.window, textvariable=self.data_text) + input_message.pack() + input_message.place(x=80, y=150) + # 确认按钮及位置 + bt_confirm = tk.Button(self.window, bg='green', text='确认', width=10, command=self.send_data) + bt_confirm.pack() + bt_confirm.place(x=125, y=220) + + # 发送要调用的信息 + def send_data(self): + message = self.name_text.get() + # 加密并封装消息 + print("正在封装并加密消息...") + enc_message = str_to_encrypt(message, self.public_key_data).ciphertext() + pack_message = "01001100" + str(enc_message) + print("正在发送消息给平台...") + self.client.send(pack_message.encode()) + print("发送成功!") + messagebox.showinfo("提示", "发送成功!") + self.window.destroy() + + # 拒绝调用数据的请求 + def send_decline_reply(self): + self.client.send(("01001001" + str(self.client.getsockname()) + "||" + "想得美哦!不给(*^▽^*)").encode()) + messagebox.showinfo("提示", "已拒绝!") + self.window.destroy() + + # 稍后处理调用数据的请求 + def wait_reply(self): + self.window.destroy() + + # 接收到sql信息的专属窗口 + def design_window(self): + if self.sql != "": + self.window = tk.Toplevel() + self.window.title("平台发来的消息") + self.window.geometry('550x320') # 设定窗口大小 + self.recent_message = "收到已授权方的sql:" + self.sql + tk.Label(self.window, bg='green', text=self.recent_message).place(x=50, y=100) + # 创建接受按钮 + accept_button = tk.Button(self.window, text="接受", width=15, command=self.send_accept_reply) + accept_button.place(x=90, y=220) + + # 创建拒绝按钮 + decline_button = tk.Button(self.window, text="拒绝", width=15, command=self.send_decline_reply) + decline_button.place(x=225, y=220) + + # 创建稍后处理按钮 + decline_button = tk.Button(self.window, text="稍后处理", width=15, command=self.wait_reply) + decline_button.place(x=360, y=220) + else: + messagebox.showinfo("提示", "暂无待处理的信息。") + +# -------------------------------------------------------------------------- + # 调用本地信息库 + def search_data(self): + output = StringIO() # 用于保存打印信息 + sys.stdout = output # 重定向sys.stdout到StringIO + print(self.name) + DataSearch.main(self.name) + sys.stdout = sys.__stdout__ + long_text = output.getvalue() + print(long_text) + # 创建显示窗口 + window = tk.Toplevel() + # 创建滚动文本部件 + roll = scrolledtext.ScrolledText(window, width=200, height=40) + # 打印超长字符串 + roll.insert(tk.END, long_text) + roll.pack() + + # --------------------------主界面的按键功能绑定-------------------------------- + # 界面按键 + def create_widgets(self): + # 创建按钮和标签等部件并使用ttk和Style进行美化 + style = Style(theme='darkly') # 指定样式主题 + self.root = style.master + button1 = ttk.Button(self.root, text="查看我的公钥", bootstyle="info-outline", + command=self.print_public_key, width=30) + button1.place(x=104, y=360) + button2 = ttk.Button(self.root, text="查看我的私钥", bootstyle="info-outline", + command=self.print_private_key, width=30) + button2.place(x=104, y=398) + button3 = ttk.Button(self.root, text="生成我的证书", bootstyle="info-outline", + command=self.print_certificate, width=30) + button3.place(x=104, y=433) + button4 = ttk.Button(self.root, text="获取平台认证", bootstyle="info-outline", + command=self.safe_connect, width=30) + button4.place(x=104, y=468) + button5 = ttk.Button(self.root, text="调用SQL查询", bootstyle="info-outline", + command=self.create_sql, width=30) + button5.place(x=104, y=503) + button6 = ttk.Button(self.root, text="发送SQL请求", bootstyle="info-outline", + command=self.send_sql, width=30) + button6.place(x=104, y=538) + button7 = ttk.Button(self.root, text="处理请求信息", bootstyle="info-outline", + command=self.design_window, width=30) + button7.place(x=104, y=573) + button8 = ttk.Button(self.root, text="查看医疗记录", bootstyle="info-outline", + command=self.search_data, width=30) + button8.place(x=104, y=608) + + # GUI界面 + def run(self): + self.root.mainloop() + + +# ----------------------------------------------------主程序---------------------------------------------------- +global server_public_key_data, photo # 使用全局变量,否则图片可能会被回收,不显示 + +# GUI界面 +app = MyClient() +app.run()