""" Author: tanglei DateTime:2024-11 #import random #random 不安全所以替换为 secrets中的算法 # 选择素域,设置椭圆曲线参数 """ import secrets class SM2_Key(): default_ecc_table = { 'n': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 'p': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 'g': '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7' 'bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0', 'a': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 'b': '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', } def __init__(self, private_key, public_key, ecc_table=default_ecc_table, mode=0, asn1=False): """ mode: 0-C1C2C3, 1-C1C3C2 (default is 1) """ self.private_key = private_key self.public_key = public_key.lstrip("04") if public_key.startswith("04") else public_key self.para_len = len(ecc_table['n']) self.ecc_a3 = ( int(ecc_table['a'], base=16) + 3) % int(ecc_table['p'], base=16) self.ecc_table = ecc_table assert mode in (0, 1), 'mode must be one of (0, 1)' self.mode = mode self.asn1 = asn1 def _kg(self, k, Point): # kP运算 Point = '%s%s' % (Point, '1') mask_str = '8' for i in range(self.para_len - 1): mask_str += '0' mask = int(mask_str, 16) Temp = Point flag = False for n in range(self.para_len * 4): if (flag): Temp = self._double_point(Temp) if (k & mask) != 0: if (flag): Temp = self._add_point(Temp, Point) else: flag = True Temp = Point k = k << 1 return self._convert_jacb_to_nor(Temp) def _double_point(self, Point): # 倍点 l = len(Point) len_2 = 2 * self.para_len if l < self.para_len * 2: return None else: x1 = int(Point[0:self.para_len], 16) y1 = int(Point[self.para_len:len_2], 16) if l == len_2: z1 = 1 else: z1 = int(Point[len_2:], 16) T6 = (z1 * z1) % int(self.ecc_table['p'], base=16) T2 = (y1 * y1) % int(self.ecc_table['p'], base=16) T3 = (x1 + T6) % int(self.ecc_table['p'], base=16) T4 = (x1 - T6) % int(self.ecc_table['p'], base=16) T1 = (T3 * T4) % int(self.ecc_table['p'], base=16) T3 = (y1 * z1) % int(self.ecc_table['p'], base=16) T4 = (T2 * 8) % int(self.ecc_table['p'], base=16) T5 = (x1 * T4) % int(self.ecc_table['p'], base=16) T1 = (T1 * 3) % int(self.ecc_table['p'], base=16) T6 = (T6 * T6) % int(self.ecc_table['p'], base=16) T6 = (self.ecc_a3 * T6) % int(self.ecc_table['p'], base=16) T1 = (T1 + T6) % int(self.ecc_table['p'], base=16) z3 = (T3 + T3) % int(self.ecc_table['p'], base=16) T3 = (T1 * T1) % int(self.ecc_table['p'], base=16) T2 = (T2 * T4) % int(self.ecc_table['p'], base=16) x3 = (T3 - T5) % int(self.ecc_table['p'], base=16) if (T5 % 2) == 1: T4 = (T5 + ((T5 + int(self.ecc_table['p'], base=16)) >> 1) - T3) % int( self.ecc_table['p'], base=16) else: T4 = (T5 + (T5 >> 1) - T3) % int(self.ecc_table['p'], base=16) T1 = (T1 * T4) % int(self.ecc_table['p'], base=16) y3 = (T1 - T2) % int(self.ecc_table['p'], base=16) form = '%%0%dx' % self.para_len form = form * 3 return form % (x3, y3, z3) def _add_point(self, P1, P2): # 点加函数,P2点为仿射坐标即z=1,P1为Jacobian加重射影坐标 len_2 = 2 * self.para_len l1 = len(P1) l2 = len(P2) if (l1 < len_2) or (l2 < len_2): return None else: X1 = int(P1[0:self.para_len], 16) Y1 = int(P1[self.para_len:len_2], 16) if (l1 == len_2): Z1 = 1 else: Z1 = int(P1[len_2:], 16) x2 = int(P2[0:self.para_len], 16) y2 = int(P2[self.para_len:len_2], 16) T1 = (Z1 * Z1) % int(self.ecc_table['p'], base=16) T2 = (y2 * Z1) % int(self.ecc_table['p'], base=16) T3 = (x2 * T1) % int(self.ecc_table['p'], base=16) T1 = (T1 * T2) % int(self.ecc_table['p'], base=16) T2 = (T3 - X1) % int(self.ecc_table['p'], base=16) T3 = (T3 + X1) % int(self.ecc_table['p'], base=16) T4 = (T2 * T2) % int(self.ecc_table['p'], base=16) T1 = (T1 - Y1) % int(self.ecc_table['p'], base=16) Z3 = (Z1 * T2) % int(self.ecc_table['p'], base=16) T2 = (T2 * T4) % int(self.ecc_table['p'], base=16) T3 = (T3 * T4) % int(self.ecc_table['p'], base=16) T5 = (T1 * T1) % int(self.ecc_table['p'], base=16) T4 = (X1 * T4) % int(self.ecc_table['p'], base=16) X3 = (T5 - T3) % int(self.ecc_table['p'], base=16) T2 = (Y1 * T2) % int(self.ecc_table['p'], base=16) T3 = (T4 - X3) % int(self.ecc_table['p'], base=16) T1 = (T1 * T3) % int(self.ecc_table['p'], base=16) Y3 = (T1 - T2) % int(self.ecc_table['p'], base=16) form = '%%0%dx' % self.para_len form = form * 3 return form % (X3, Y3, Z3) def _convert_jacb_to_nor(self, Point): # Jacobian加重射影坐标转换成仿射坐标 len_2 = 2 * self.para_len x = int(Point[0:self.para_len], 16) y = int(Point[self.para_len:len_2], 16) z = int(Point[len_2:], 16) z_inv = pow( z, int(self.ecc_table['p'], base=16) - 2, int(self.ecc_table['p'], base=16)) z_invSquar = (z_inv * z_inv) % int(self.ecc_table['p'], base=16) z_invQube = (z_invSquar * z_inv) % int(self.ecc_table['p'], base=16) x_new = (x * z_invSquar) % int(self.ecc_table['p'], base=16) y_new = (y * z_invQube) % int(self.ecc_table['p'], base=16) z_new = (z * z_inv) % int(self.ecc_table['p'], base=16) if z_new == 1: form = '%%0%dx' % self.para_len form = form * 2 return form % (x_new, y_new) else: return None def generate_keypair(self): """ 生成SM2公私钥对 私钥为随机生成的小于n的整数 公钥通过基点乘以私钥得到 :return: (private_key, public_key) """ # 生成一个随机的私钥,范围在[1, n-1]之间 #private_key = '%064x' % random.randint(1, int(self.ecc_table['n'], 16) - 1) private_key = '%064x' % secrets.randbelow(int(self.ecc_table['n'], 16) - 1) # 通过私钥和基点计算公钥 public_key = self._kg(int(private_key, 16), self.ecc_table['g']) # 公钥是椭圆曲线点的 x 和 y 坐标,格式为 '04 + x + y' #public_key = '04' + public_key 不带04 return public_key.upper(),private_key.upper() def main(): #private_key1 = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207' #public_key1 = 'B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5' private_key1 = '' public_key1 = '' ecc_table1 = SM2_Key.default_ecc_table my_sm21 = SM2_Key(private_key=private_key1, public_key=public_key1, ecc_table=ecc_table1, mode=1) public_key, private_key = my_sm21.generate_keypair() print(f'public_key:{public_key}') print(f'private_key:{private_key}') if __name__ == '__main__': main()