赞
踩
#声明:本文创作内容含代码均为个人创作所得,允许学习、传阅,不得用于商业用途#
#本文包含国密SM4从算法到硬件实现的全部#
#实践会让你更加透彻理解算法原理,才能让知识灌入大脑#
SM4是中国密码局公布的块加密算法,是一种对称算法,与国际上AES算法相类似(专类文件有介绍AES)。使用场景比如数据存储和传送的时候,为了防止被窃取,我们可以先将其加密,然后再存储、传送,这样数据安全才有保障。
建议国密官网下载“SM4 Block Cipher Algorithm” PDF查阅
SM4加解密的明文和秘钥的长度均为128bit,加解密后,密文的长度也是128bit;
假设秘钥用MK表示,将其分成四个字,每个字32bit,
1. 输入秘钥和系统参数,经过32轮迭代运算后,得到32个轮秘钥,每个秘钥32bit;
2. 输入密文和轮秘钥经过32轮迭代运算,每轮迭代需要一个轮密码,得到中间密文;
3. 将上述中间密文反转后得到最终密文;
加密迭代过程如下:
其中rki是第一步128bit秘钥经过32轮迭代后生成的32个轮秘钥。那这些轮秘钥生成方式和加解迭代函数F具体形式是啥呢?往下看:
轮秘钥生成方式:
输入的128bit密钥按每32bit划分为MK0,MK1,MK2,MK3,FK0,FK1,FK2,FK3是固定已知的参数,其中 FK0=A3B1BAC6,FK1=56AA3350,FK2=6777D9197,FK3=B27022DC;输入的秘钥和固定参数异或后得到初始值K0,K1,K2,K3,然后再经过32轮迭代;参数Ki是固定已知的,如下图所示:
迭代函数T`是非线性的,表达式如下:
,其中 <<<是循环移位,
T(B)是一个查找表,表格如下:
查找表介绍:这个查找表是一个非线性函数,XY的交叉点就是输出值,例如,X=C,Y=3,那输出值是92,,因为T函数的输入是32bit,而查找表是基于8bit的,所以需要将T函数的32bit输入划分为4个byte,每个byte经过查找表后结果再拼起来得到一个32bit输出,然后再经过函数L的逻辑运算;
举个例子:B=1A02344C, T(B) = 13E9C9E6
经过上述操作,我们可以得到32个轮密钥
加密迭代计算:
其中 ,其中
其中T(B)是和轮密钥生成一样的查找表。
经过32轮迭代后,可以得到X32,X33,X34,X35
密文反转:
输出密文为:Y=(X35,X34,X33,X32)
下面图片展示了第一轮迭代过程,密钥的迭代结构是一样的,唯一区别是L(B) 替换为L`(B)
代码阅读完成后还是建议大家自己亲自手写一遍,加强对算法和python语法的熟悉
说明:加密数据和key是16进制的字符串输入;大家在抄写查找表一定要细心,这里面是一个坑;相比于SM3,这个算法Python实现起来更简单。这里面数据运算一般是基于32bit,也就是4个16进制数。
- class Sm4Algorithm:
-
- FK = ['a3b1bac6', '56aa3350', '677d9197', 'b27022dc']
-
- CK = ['00070e15', '1c232a31', '383f464d', '545b6269',
- '70777e85', '8c939aa1', 'a8afb6bd', 'c4cbd2d9',
- 'e0e7eef5', 'fc030a11', '181f262d', '343b4249',
- '50575e65', '6c737a81', '888f969d', 'a4abb2b9',
- 'c0c7ced5', 'dce3eaf1', 'f8ff060d', '141b2229',
- '30373e45', '4c535a61', '686f767d', '848b9299',
- 'a0a7aeb5', 'bcc3cad1', 'd8dfe6ed', 'f4fb0209',
- '10171e25', '2c333a41', '484f565d', '646b7279']
-
- TABLE = {'00': 'd6', '01': '90', '02': 'e9', '03': 'fe', '04': 'cc', '05': 'e1', '06': '3d', '07': 'b7',
- '08': '16', '09': 'b6', '0a': '14', '0b': 'c2', '0c': '28', '0d': 'fb', '0e': '2c', '0f': '05',
-
- '10': '2b', '11': '67', '12': '9a', '13': '76', '14': '2a', '15': 'be', '16': '04', '17': 'c3',
- '18': 'aa', '19': '44', '1a': '13', '1b': '26', '1c': '49', '1d': '86', '1e': '06', '1f': '99',
-
- '20': '9c', '21': '42', '22': '50', '23': 'f4', '24': '91', '25': 'ef', '26': '98', '27': '7a',
- '28': '33', '29': '54', '2a': '0b', '2b': '43', '2c': 'ed', '2d': 'cf', '2e': 'ac', '2f': '62',
-
- '30': 'e4', '31': 'b3', '32': '1c', '33': 'a9', '34': 'c9', '35': '08', '36': 'e8', '37': '95',
- '38': '80', '39': 'df', '3a': '94', '3b': 'fa', '3c': '75', '3d': '8f', '3e': '3f', '3f': 'a6',
-
- '40': '47', '41': '07', '42': 'a7', '43': 'fc', '44': 'f3', '45': '73', '46': '17', '47': 'ba',
- '48': '83', '49': '59', '4a': '3c', '4b': '19', '4c': 'e6', '4d': '85', '4e': '4f', '4f': 'a8',
-
- '50': '68', '51': '6b', '52': '81', '53': 'b2', '54': '71', '55': '64', '56': 'da', '57': '8b',
- '58': 'f8', '59': 'eb', '5a': '0f', '5b': '4b', '5c': '70', '5d': '56', '5e': '9d', '5f': '35',
-
- '60': '1e', '61': '24', '62': '0e', '63': '5e', '64': '63', '65': '58', '66': 'd1', '67': 'a2',
- '68': '25', '69': '22', '6a': '7c', '6b': '3b', '6c': '01', '6d': '21', '6e': '78', '6f': '87',
-
- '70': 'd4', '71': '00', '72': '46', '73': '57', '74': '9f', '75': 'd3', '76': '27', '77': '52',
- '78': '4c', '79': '36', '7a': '02', '7b': 'e7', '7c': 'a0', '7d': 'c4', '7e': 'c8', '7f': '9e',
-
- '80': 'ea', '81': 'bf', '82': '8a', '83': 'd2', '84': '40', '85': 'c7', '86': '38', '87': 'b5',
- '88': 'a3', '89': 'f7', '8a': 'f2', '8b': 'ce', '8c': 'f9', '8d': '61', '8e': '15', '8f': 'a1',
-
- '90': 'e0', '91': 'ae', '92': '5d', '93': 'a4', '94': '9b', '95': '34', '96': '1a', '97': '55',
- '98': 'ad', '99': '93', '9a': '32', '9b': '30', '9c': 'f5', '9d': '8c', '9e': 'b1', '9f': 'e3',
-
- 'a0': '1d', 'a1': 'f6', 'a2': 'e2', 'a3': '2e', 'a4': '82', 'a5': '66', 'a6': 'ca', 'a7': '60',
- 'a8': 'c0', 'a9': '29', 'aa': '23', 'ab': 'ab', 'ac': '0d', 'ad': '53', 'ae': '4e', 'af': '6f',
-
- 'b0': 'd5', 'b1': 'db', 'b2': '37', 'b3': '45', 'b4': 'de', 'b5': 'fd', 'b6': '8e', 'b7': '2f',
- 'b8': '03', 'b9': 'ff', 'ba': '6a', 'bb': '72', 'bc': '6d', 'bd': '6c', 'be': '5b', 'bf': '51',
-
- 'c0': '8d', 'c1': '1b', 'c2': 'af', 'c3': '92', 'c4': 'bb', 'c5': 'dd', 'c6': 'bc', 'c7': '7f',
- 'c8': '11', 'c9': 'd9', 'ca': '5c', 'cb': '41', 'cc': '1f', 'cd': '10', 'ce': '5a', 'cf': 'd8',
-
- 'd0': '0a', 'd1': 'c1', 'd2': '31', 'd3': '88', 'd4': 'a5', 'd5': 'cd', 'd6': '7b', 'd7': 'bd',
- 'd8': '2d', 'd9': '74', 'da': 'd0', 'db': '12', 'dc': 'b8', 'dd': 'e5', 'de': 'b4', 'df': 'b0',
-
- 'e0': '89', 'e1': '69', 'e2': '97', 'e3': '4a', 'e4': '0c', 'e5': '96', 'e6': '77', 'e7': '7e',
- 'e8': '65', 'e9': 'b9', 'ea': 'f1', 'eb': '09', 'ec': 'c5', 'ed': '6e', 'ee': 'c6', 'ef': '84',
-
- 'f0': '18', 'f1': 'f0', 'f2': '7d', 'f3': 'ec', 'f4': '3a', 'f5': 'dc', 'f6': '4d', 'f7': '20',
- 'f8': '79', 'f9': 'ee', 'fa': '5f', 'fb': '3e', 'fc': 'd7', 'fd': 'cb', 'fe': '39', 'ff': '48'}
-
- def x_box(self, x):
- x_str = '{:08x}'.format(x)
- y_str = ''
- for i in range(4):
- y_str = y_str + self.TABLE[x_str[i*2:i*2+2]]
- return int(y_str, 16) & 0xFFFFFFFF
-
- def rotate_left(self, a, k):
- k = k % 32
- return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32-k))
-
- def l_of_plaintext(self, x):
- return (x ^ self.rotate_left(x,2) ^ self.rotate_left(x,10) ^ self.rotate_left(x,18) ^self.rotate_left(x,24)) & 0xFFFFFFFF
-
- def l_of_key(self, x):
- return (x ^ self.rotate_left(x,13) ^ self.rotate_left(x,23)) & 0xFFFFFFFF
-
- def t_of_plaintext(self,x):
- return self.l_of_plaintext(self.x_box(x))
-
- def t_of_key(self, x):
- return self.l_of_key(self.x_box(x))
-
- def key_output(self, key):
- mk0 = int(key[8*0:8*1], 16) & 0xFFFFFFFF
- mk1 = int(key[8*1:8*2], 16) & 0xFFFFFFFF
- mk2 = int(key[8*2:8*3], 16) & 0xFFFFFFFF
- mk3 = int(key[8*3:8*4], 16) & 0xFFFFFFFF
-
- k0 = mk0 ^ (int(self.FK[0], 16) & 0xFFFFFFFF)
- k1 = mk1 ^ (int(self.FK[1], 16) & 0xFFFFFFFF)
- k2 = mk2 ^ (int(self.FK[2], 16) & 0xFFFFFFFF)
- k3 = mk3 ^ (int(self.FK[3], 16) & 0xFFFFFFFF)
-
- k = [0] * 36
- k[0:4] = [k0, k1, k2, k3]
- rk = [0] * 32
- for i in range(32):
- tmp = k[i+1] ^ k[i+2] ^ k[i+3] ^ (int(self.CK[i], 16) & 0xFFFFFFFF)
- k[i+4] = k[i] ^ self.t_of_key(tmp)
- # print(i,hex(k[i+4]))
- rk[i] = k[i+4]
- return rk
-
- def encryption(self, x, key):
- ciphertext = [0] * 36
- ciphertext[0] = int(x[8*0:8*1], 16) & 0xFFFFFFFF
- ciphertext[1] = int(x[8*1:8*2], 16) & 0xFFFFFFFF
- ciphertext[2] = int(x[8*2:8*3], 16) & 0xFFFFFFFF
- ciphertext[3] = int(x[8*3:8*4], 16) & 0xFFFFFFFF
-
- get_key = key
- rk = self.key_output(get_key)
-
- for i in range(32):
- tmp = ciphertext[i+1] ^ ciphertext[i+2] ^ ciphertext[i+3] ^ rk[i]
- ciphertext[i+4] = ciphertext[i] ^ self.t_of_plaintext(tmp)
- # print(i+4,hex(ciphertext[i+4]))
-
- y = '{:08x}'.format(ciphertext[35]) + '{:08x}'.format(ciphertext[34]) + '{:08x}'.format(ciphertext[33]) + '{:08x}'.format(ciphertext[32])
- return y
-
- if __name__ == '__main__':
- get_class = Sm4Algorithm()
- # case 1
- date = get_class.encryption('0123456789abcdeffedcba9876543210', '0123456789abcdeffedcba9876543210') # case1
- print(date)
- print(type(date))
-
- # case 2
- for i in range(1000000):
- if i == 0 :
- data = '0123456789abcdeffedcba9876543210'
- output = get_class.encryption(data, '0123456789abcdeffedcba9876543210')
- else :
- tmp = output
- output= get_class.encryption(tmp, '0123456789abcdeffedcba9876543210')
-
- if i == 999999:
- print(output)
“后续待补充”
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。