节外生枝,我居然还会密码学
# python环境:3.7
from random import choice
from math import ceil
IV="59173e5a 8a3472c7 96273422 421e9b6a 132359aa 97612564 aa8916a7 139614b6" #设置初始值
IV = int(IV.replace(" ", ""), 16)
a = []
for i in range(0, 8):
a.append(0)
a[i] = (IV >> ((7 - i) * 32)) & 0xFFFFFFFF
IV = a
def left(a, k): #字符串按比特向左移位
k = k % 32
return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k))
T_j = []
for i in range(0, 16):
T_j.append(0)
T_j[i] = 0x3764ab85
for i in range(16, 64):
T_j.append(0)
T_j[i] = 0x84369d8a
def FF_j(X, Y, Z, j): #布尔函数
if 0 <= j and j < 16:
ret = X ^ Y ^ Z
elif 16 <= j and j < 64:
ret = (X & Y) | (X & Z) | (Y & Z)
return ret
def GG_j(X, Y, Z, j): #布尔函数
if 0 <= j and j < 16:
ret = X ^ Y ^ Z
elif 16 <= j and j < 64:
#ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)
ret = (X & Y) | ((~ X) & Z)
return ret
def P0(X): #置换函数
return X ^ (left(X, 9)) ^ (left(X, 17))
def P1(X): #置换函数
return X ^ (left(X, 15)) ^ (left(X, 23))
def CF(V_i, B_i): #压缩函数
W = []
for i in range(16):
weight = 0x1000000
data = 0
for k in range(i*4,(i+1)*4):
data = data + B_i[k]*weight
weight = int(weight/0x100)
W.append(data)
for j in range(16, 68):
W.append(0)
W[j] = P1(W[j-16] ^ W[j-9] ^ (left(W[j-3], 15))) ^ (left(W[j-13], 7)) ^ W[j-6]
str1 = "%08x" % W[j]
W_1 = []
for j in range(0, 64):
W_1.append(0)
W_1[j] = W[j] ^ W[j+4]
str1 = "%08x" % W_1[j]
A, B, C, D, E, F, G, H = V_i
for j in range(0, 64):
SS1 = left(((left(A, 12)) + E + (left(T_j[j], j))) & 0xFFFFFFFF, 7)
SS2 = SS1 ^ (left(A, 12))
TT1 = (FF_j(A, B, C, j) + D + SS2 + W_1[j]) & 0xFFFFFFFF
TT2 = (GG_j(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
D = C
C = left(B, 9)
B = A
A = TT1
H = G
G = left(F, 19)
F = E
E = P0(TT2)
A = A & 0xFFFFFFFF
B = B & 0xFFFFFFFF
C = C & 0xFFFFFFFF
D = D & 0xFFFFFFFF
E = E & 0xFFFFFFFF
F = F & 0xFFFFFFFF
G = G & 0xFFFFFFFF
H = H & 0xFFFFFFFF
V_i_1 = []
V_i_1.append(A ^ V_i[0])
V_i_1.append(B ^ V_i[1])
V_i_1.append(C ^ V_i[2])
V_i_1.append(D ^ V_i[3])
V_i_1.append(E ^ V_i[4])
V_i_1.append(F ^ V_i[5])
V_i_1.append(G ^ V_i[6])
V_i_1.append(H ^ V_i[7])
return V_i_1
def hashmsg(msg):
# print(msg)
len1 = len(msg)
reserve1 = len1 % 64
msg.append(0x80)
reserve1 = reserve1 + 1
# 56-64, add 64 byte
range_end = 56
if reserve1 > range_end:
range_end = range_end + 64
for i in range(reserve1, range_end):
msg.append(0x00)
bit_length = (len1) * 8
bit_length_str = [bit_length % 0x100]
for i in range(7):
bit_length = int(bit_length / 0x100)
bit_length_str.append(bit_length % 0x100)
for i in range(8):
msg.append(bit_length_str[7-i])
group_count = round(len(msg) / 64)
B = []
for i in range(0, group_count):
B.append(msg[i*64:(i+1)*64])
V = []
V.append(IV)
for i in range(0, group_count):
V.append(CF(V[i], B[i]))
y = V[i+1]
result = ""
for i in y:
result = '%s%08x' % (result, i)
return result
def str2byte(msg): # 字符串转换成byte数组
ml = len(msg)
msg_byte = []
msg_bytearray = msg.encode('utf-8')
for i in range(ml):
msg_byte.append(msg_bytearray[i])
return msg_byte
def byte2str(msg): # byte数组转字符串
ml = len(msg)
str1 = b""
for i in range(ml):
str1 += b'%c' % msg[i]
return str1.decode('utf-8')
def hex2byte(msg): # 16进制字符串转换成byte数组
ml = len(msg)
if ml % 2 != 0:
msg = '0'+ msg
ml = int(len(msg)/2)
msg_byte = []
for i in range(ml):
msg_byte.append(int(msg[i*2:i*2+2],16))
return msg_byte
def byte2hex(msg): # byte数组转换成16进制字符串
ml = len(msg)
hexstr = ""
for i in range(ml):
hexstr = hexstr + ('%02x'% msg[i])
return hexstr
def Hash_sm3(msg,Hexstr = 0):
if(Hexstr):
msg_byte = hex2byte(msg)
else:
msg_byte = str2byte(msg)
return hashmsg(msg_byte)
def KDF(Z,klen): # 密钥派生函数,Z为16进制表示的比特串(str),klen为密钥长度(单位byte)
klen = int(klen)
ct = 0x00000001
rcnt = ceil(klen/32)
Zin = hex2byte(Z)
Ha = ""
for i in range(rcnt):
msg = Zin + hex2byte('%08x'% ct)
# print(msg)
Ha = Ha + hashmsg(msg)
# print(Ha)
ct += 1
return Ha[0: klen * 2]
# 选择素域,设置椭圆曲线参数,以参考曲线为例子
sm2_N = int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16)
sm2_P = int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)
sm2_G = '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0' # G点
sm2_a = int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',16)
sm2_b = int('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',16)
sm2_a_3 = (sm2_a + 3) % sm2_P # 倍点用到的中间值
Fp = 256
def getrandomstr(strlen):
letterlist = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
str = ''
for i in range(strlen):
a = choice(letterlist)
str = '%s%s' % (str,a)
return str
def kG(k, Point,len_para): # kP运算 选择一个私有密钥k,并生成公开密钥K=kG
Point = '%s%s' % (Point, '1')
mask_str = '8'
for i in range(len_para-1):
mask_str += '0'
# print(mask_str)
mask = int(mask_str, 16)
Temp = Point
flag = False
for n in range(len_para * 4):
if (flag):
Temp = DoublePoint(Temp,len_para)
if (k & mask) != 0:
if (flag):
Temp = AddPoint(Temp, Point,len_para)
else:
flag = True
Temp = Point
k = k << 1
return ConvertJacb2Nor(Temp,len_para)
def DoublePoint(Point,len_para): # 倍点
l = len(Point)
len_2 = 2 * len_para
if l< len_para*2:
return None
else:
x1 = int(Point[0:len_para], 16)
y1 = int(Point[len_para:len_2], 16)
if l == len_2:
z1 = 1
else:
z1 = int(Point[len_2:], 16)
T6 = (z1 * z1) % sm2_P
T2 = (y1 * y1) % sm2_P
T3 = (x1 + T6) % sm2_P
T4 = (x1 - T6) % sm2_P
T1 = (T3 * T4) % sm2_P
T3 = (y1 * z1) % sm2_P
T4 = (T2 * 8) % sm2_P
T5 = (x1 * T4) % sm2_P
T1 = (T1 * 3) % sm2_P
T6 = (T6 * T6) % sm2_P
T6 = (sm2_a_3 * T6) % sm2_P
T1 = (T1 + T6) % sm2_P
z3 = (T3 + T3) % sm2_P
T3 = (T1 * T1) % sm2_P
T2 = (T2 * T4) % sm2_P
x3 = (T3 - T5) % sm2_P
if (T5 % 2) == 1:
T4 = (T5 + ((T5 + sm2_P) >> 1) - T3) % sm2_P
else:
T4 = (T5 + (T5 >> 1) - T3) % sm2_P
T1 = (T1 * T4) % sm2_P
y3 = (T1 - T2) % sm2_P
form = '%%0%dx' % len_para
form = form * 3
return form % (x3, y3, z3)
def AddPoint(P1, P2,len_para): # 点加函数
len_2 = 2 * len_para
l1 = len(P1)
l2 = len(P2)
if (l1 < len_2) or (l2 < len_2):
return None
else:
X1 = int(P1[0:len_para], 16)
Y1 = int(P1[len_para:len_2], 16)
if (l1 == len_2):
Z1 = 1
else:
Z1 = int(P1[len_2:], 16)
x2 = int(P2[0:len_para], 16)
y2 = int(P2[len_para:len_2], 16)
T1 = (Z1 * Z1) % sm2_P
T2 = (y2 * Z1) % sm2_P
T3 = (x2 * T1) % sm2_P
T1 = (T1 * T2) % sm2_P
T2 = (T3 - X1) % sm2_P
T3 = (T3 + X1) % sm2_P
T4 = (T2 * T2) % sm2_P
T1 = (T1 - Y1) % sm2_P
Z3 = (Z1 * T2) % sm2_P
T2 = (T2 * T4) % sm2_P
T3 = (T3 * T4) % sm2_P
T5 = (T1 * T1) % sm2_P
T4 = (X1 * T4) % sm2_P
X3 = (T5 - T3) % sm2_P
T2 = (Y1 * T2) % sm2_P
T3 = (T4 - X3) % sm2_P
T1 = (T1 * T3) % sm2_P
Y3 = (T1 - T2) % sm2_P
form = '%%0%dx' % len_para
form = form * 3
return form % (X3, Y3, Z3)
def ConvertJacb2Nor(Point,len_para): # 仿射坐标转换
len_2 = 2 * len_para
x = int(Point[0:len_para], 16)
y = int(Point[len_para:len_2], 16)
z = int(Point[len_2:], 16)
# z_inv = Inverse(z, P)
z_inv = pow(z, sm2_P - 2, sm2_P)
z_invSquar = (z_inv * z_inv) % sm2_P
z_invQube = (z_invSquar * z_inv) % sm2_P
x_new = (x * z_invSquar) % sm2_P
y_new = (y * z_invQube) % sm2_P
z_new = (z * z_inv) % sm2_P
if z_new == 1:
form = '%%0%dx' % len_para
form = form * 2
return form % (x_new, y_new)
else:
print ("error")
return None
def Inverse(data, M,len_para): # 求逆
tempM = M - 2
mask_str = '8'
for i in range(len_para-1):
mask_str += '0'
mask = int(mask_str, 16)
tempA = 1
tempB = data
for i in range(len_para*4):
tempA = (tempA * tempA) % M
if (tempM & mask) != 0:
tempA = (tempA * tempB) % M
mask = mask >> 1
return tempA
def Verify(Sign, E, PA,len_para): # 验签函数,Sign签名r||s,E消息hash,PA公钥
r = int(Sign[0:len_para], 16)
s = int(Sign[len_para:2*len_para], 16)
e = int(E, 16)
t = (r + s) % sm2_N
if t == 0:
return 0
P1 = kG(s, sm2_G,len_para)
P2 = kG(t, PA,len_para)
# print(P1)
# print(P2)
if P1 == P2:
P1 = '%s%s' % (P1, 1)
P1 = DoublePoint(P1,len_para)
else:
P1 = '%s%s' % (P1, 1)
P1 = AddPoint(P1, P2,len_para)
P1 = ConvertJacb2Nor(P1,len_para)
x = int(P1[0:len_para], 16)
return (r == ((e + x) % sm2_N))
def Sign(E, DA, K,len_para,Hexstr = 0): # 签名函数, E消息的hash,DA私钥,K随机数,均为16进制字符串
if Hexstr:
e = int(E, 16) # 输入消息本身是16进制字符串
else:
E = E.encode('utf-8')
E = E.hex() # 消息转化为16进制字符串
e = int(E, 16)
d = int(DA, 16)
k = int(K, 16)
P1 = kG(k, sm2_G,len_para)
x = int(P1[0:len_para], 16)
R = ((e + x) % sm2_N)
if R == 0 or R + k == sm2_N:
return None
d_1 = pow(d+1, sm2_N - 2, sm2_N)
S = (d_1*(k + R) - R) % sm2_N
if S == 0:
return None
else:
return '%064x%064x' % (R,S)
def Encrypt(M,PA,len_para,Hexstr = 0):# 加密函数,M消息,PA公钥
if Hexstr:
msg = M # 输入消息本身是16进制字符串
else:
msg = M.encode('utf-8')
msg = msg.hex() # 消息转化为16进制字符串
k = getrandomstr(len_para)
C1 = kG(int(k,16),sm2_G,len_para)
# print('C1 = %s'%C1)
xy = kG(int(k,16),PA,len_para)
# print('xy = %s' % xy)
x2 = xy[0:len_para]
y2 = xy[len_para:2*len_para]
ml = len(msg)
# print('ml = %d'% ml)
t = KDF(xy,ml/2)
# print(t)
if int(t,16)==0:
return None
else:
form = '%%0%dx' % ml
C2 = form % (int(msg,16) ^ int(t,16))
C3 = Hash_sm3('%s%s%s'% (x2,msg,y2),1)
return '%s%s%s' % (C1,C3,C2)
def Decrypt(C,DA,len_para): # 解密函数,C密文(16进制字符串),DA私钥
len_2 = 2 * len_para
len_3 = len_2 + 64
C1 = C[0:len_2]
C3 = C[len_2:len_3]
C2 = C[len_3:]
xy = kG(int(DA,16),C1,len_para)
x2 = xy[0:len_para]
y2 = xy[len_para:len_2]
cl = len(C2)
t = KDF(xy, cl/2)
if int(t,16) == 0:
return None
else:
form = '%%0%dx' % cl
M = form % (int(C2,16) ^ int(t,16))
# print('M = %s' % M)
u = Hash_sm3('%s%s%s'% (x2,M,y2),1)
if (u == C3):
return M
else:
return None
if __name__ == '__main__':
print(Hash_sm3("abc"))
len_para = int(Fp / 4)
print(len_para)
e = getrandomstr(len_para)
d = getrandomstr(len_para)
k = getrandomstr(len_para)
d = '3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8'
Pa = kG(int(d, 16), sm2_G,len_para)
Sig = Sign(e,d,k,len_para,1)
print(Verify(Sig,e,Pa,len_para))
print(Pa)
e = "期中考试"
print('M = %s' % e)
C = Encrypt(e,Pa,len_para,0)
print('C = %s' % C)
print('Decrypt')
m = Decrypt(C,d,len_para)
M = bytes.fromhex(m)
print(M.decode())