sm3加密算法(即:sm3密码杂凑算法)是由国家密码管理局发布的,目前金融相关公司中对信息进行不可逆加密时,普遍采用该算法。
该算法主要经过以下几个步骤(摘自参考1):
1) 消息填充:
假设消息m 的长度为l 比特。首先将比特“1”添加到消息的末尾,再添加k 个“0”,k是满 足l + 1 + k ≡ 448mod512 的最小的非负整数。然后再添加一个64位比特串,该比特串是长度l的二进 制表示。填充后的消息m'的比特长度为512的倍数。
2)消息分组
将填充后的消息m' 按照512比特进行分组
其中
3)消息扩展
将消息分组B(i)按以下方法扩展生成132个字,用于压缩函 数CF。详细方法请参考官方文档
4)压缩函数CF
详细方法请参考官方文档
5)迭代压缩
将分组后的消息m'按下列方式迭代:
FOR i=0 TO n-1
END FOR
其中CF是压缩函数,为256比特初始值IV,为填充后的消息分组,迭代压缩的结果为
(官方文档一定要看,看完后对该算法就有个比较清晰的认识了)
完整代码如下:
- # -*- coding:utf-8 -*-
-
- """
- :author: liyebei
- :date: 2022-08-06
- :description: SM3加密算法。 适用于python2.7+, python3.5+(用python3时暂不支持对中文的加密)
- """
-
- # 初始值
- iv = 0x7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e
- MAX = 2 ** 32
-
-
- def str2bin(msg):
- """
- 字符串转比特串
- :param msg: 字符串
- :return: 转换之后的比特串
- """
- l = len(msg)
- s_dec = 0
- for m in msg:
- s_dec = s_dec << 8
- s_dec += ord(m)
-
- msg_bin = bin(s_dec)[2:].zfill(l * 8)
- return msg_bin
-
-
- def int2bin(a, k):
- """
- 将整数转化为比特串
- :param a: 待转化的整数
- :param k: 比特串的长度
- :return: 转化后长度为k的比特串
- """
- return bin(a)[2:].zfill(k)
-
-
- def int2hex(a, k):
- """
- 整数转化为16进制的字符串,前补0补齐k位数
- :param a: 整数
- :param k: 补齐后的字符串长度
- :return: 转化后的16进制形式字符串
- """
- return hex(a)[2:].zfill(k)
-
-
- def bin2hex(a, k):
- """
- 比特串转化为16进制的字符串,前补0补齐k位数
- :param a: 待转化的比特串
- :param k: 补齐后的字符串长度
- :return: 长度为k的16进制字符串
- """
- return hex(int(a, 2))[2:].zfill(k)
-
-
- def msg_fill(msg_bin):
- """
- 对消息进行填充。填充后的消息满足:(l+1+k) mod 512 = 448 k取最小值
- :param msg_bin: 比特串形式的消息
- :return: 填充后的消息(比特串形式)
- """
- l = len(msg_bin)
- k = 448 - (l + 1) % 512
- if k < 0:
- k += 512
-
- l_bin = int2bin(l, 64)
- msg_filled = msg_bin + '1' + '0' * k + l_bin
-
- return msg_filled
-
-
- def iteration_func(msg):
- """
- 迭代压缩
- :param msg: 填充后的比特串消息
- :return: 迭代压缩后的消息,长度为64的字符串
- """
- # 将填充后的消息按512比特进行分组
- n = len(msg) // 512
- b = []
- for i in range(n):
- b.append(msg[512 * i:512 * (i + 1)])
-
- # 对消息进行迭代压缩
- v = [int2bin(iv, 256)]
- for i in range(n):
- v.append(cf(v[i], b[i]))
-
- return bin2hex(v[n], 64)
-
-
- def msg_extension(bi):
- """
- 消息扩展, 将消息分组bi扩展生成132个字W0, W1, · · · , W67, W0', W1', · · · , W63',用于压缩函数CF
- :param bi: 填充后的消息分组,长度为512的比特串
- :return: w, w1 扩展后的消息,w为68字的list, w1为64字的list。字以整数存储
- """
- # 将消息分组Bi划分为16个字W0, W1, · · · , W15
- w = []
- for j in range(16):
- w.append(int(bi[j * 32:(j + 1) * 32], 2))
-
- for j in range(16, 68):
- w_j = p1(w[j - 16] ^ w[j - 9] ^ rotate_left(w[j - 3], 15)) ^ rotate_left(w[j - 13], 7) ^ w[j - 6]
- w.append(w_j)
-
- w1 = []
- for j in range(64):
- w1.append(w[j] ^ w[j + 4])
-
- return w, w1
-
-
- def cf(vi, bi):
- """
- 压缩函数
- :param vi: 比特串(256位)
- :param bi: 填充后的消息分组(512位比特串)
- :return: 压缩后的比特串(256位)
- """
- # 对bi进行消息扩展
- w, w1 = msg_extension(bi)
-
- # 将vi拆分为 a~h 8个字
- t = []
- for i in range(8):
- t.append(int(vi[i * 32:(i + 1) * 32], 2))
- a, b, c, d, e, f, g, h = t
-
- for j in range(64):
- ss1 = rotate_left((rotate_left(a, 12) + e + rotate_left(t_j(j), j)) % MAX, 7)
- ss2 = ss1 ^ rotate_left(a, 12)
- tt1 = (ff(a, b, c, j) + d + ss2 + w1[j]) % MAX
- tt2 = (gg(e, f, g, j) + h + ss1 + w[j]) % MAX
- d = c
- c = rotate_left(b, 9)
- b = a
- a = tt1
- h = g
- g = rotate_left(f, 19)
- f = e
- e = p0(tt2)
-
- vi_1 = int2bin(a, 32) + int2bin(b, 32) + int2bin(c, 32) + int2bin(d, 32) \
- + int2bin(e, 32) + int2bin(f, 32) + int2bin(g, 32) + int2bin(h, 32)
- vi_1 = int(vi_1, 2) ^ int(vi, 2)
-
- return int2bin(vi_1, 256)
-
-
- def rotate_left(a, k):
- """
- (字)循环左移k比特运算
- :param a: 待按位左移的比特串
- :param k: 左移位数
- :return:
- """
- k = k % 32
- return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k))
-
-
- def p0(x):
- """
- 置换函数P0
- :param x: 待置换的消息(字)
- :return: 置换后的消息(字)
- """
- return x ^ rotate_left(x, 9) ^ rotate_left(x, 17)
-
-
- def p1(x):
- """
- 置换函数P1
- :param x: 待置换的消息(字)
- :return: 置换后的消息(字)
- """
- return x ^ rotate_left(x, 15) ^ rotate_left(x, 23)
-
-
- def t_j(j):
- """
- 常量
- """
- if j <= 15:
- return 0x79cc4519
- else:
- return 0x7a879d8a
-
-
- def ff(x, y, z, j):
- """
- 布尔函数ff
- """
- if j <= 15:
- return x ^ y ^ z
- else:
- return (x & y) | (x & z) | (y & z)
-
-
- def gg(x, y, z, j):
- """
- 布尔函数gg
- """
- if j <= 15:
- return x ^ y ^ z
- else:
- return (x & y) | ((x ^ 0xFFFFFFFF) & z)
-
-
- def sm3(msg):
- """
- sm3加密主函数
- :param msg: 待加密的字符串
- :return: sm3加密后的字符串
- """
- # 字符串转化为比特串
- s_bin = str2bin(msg)
-
- # 对消息进行填充
- s_fill = msg_fill(s_bin)
-
- # 对填充后的消息进行迭代压缩
- s_sm3 = iteration_func(s_fill)
-
- # 对于python2需要删除因长整型而引入的末尾的L字符,python3不存在该问题
- return s_sm3.upper().replace("L", "")
-
-
- if __name__ == "__main__":
- s1 = 'abc'
-
- s1_sm3 = sm3(s1)
- print("{} ==> {}".format(s1, s1_sm3))
-
- s2 = 'hello'
- s2_sm3 = sm3(s2)
- print("{} ==> {}".format(s2, s2_sm3))
代码执行结果:
abc ==> 66C7F0F462EEEDD9D1F2D46BDC10E4E24167C4875CF2F7A2297DA02B8F4BA8E0
hello ==> BECBBFAAE6548B8BF0CFCAD5A27183CD1BE6093B1CCECCC303D9C61D0A645268
参考1:国家密码管理局发布的《SM3密码杂凑算法》