当前位置:   article > 正文

SM4算法原理和硬件实现_使用硬件描述语言实现sm4加密算法

使用硬件描述语言实现sm4加密算法

#声明:本文创作内容含代码均为个人创作所得,允许学习、传阅,不得用于商业用途#

#本文包含国密SM4从算法到硬件实现的全部# 

#实践会让你更加透彻理解算法原理,才能让知识灌入大脑#

一:背景

SM4是中国密码局公布的块加密算法,是一种对称算法,与国际上AES算法相类似(专类文件有介绍AES)。使用场景比如数据存储和传送的时候,为了防止被窃取,我们可以先将其加密,然后再存储、传送,这样数据安全才有保障。

二:算法说明

建议国密官网下载“SM4 Block Cipher Algorithm” PDF查阅

SM4加解密的明文和秘钥的长度均为128bit,加解密后,密文的长度也是128bit;

假设秘钥用MK表示,将其分成四个字,每个字32bit,eq?%5Cmathrm%7BMK%20%3D%20MK_%7B0%7D+MK_%7B1%7D+MK_%7B2%7D+MK_%7B3%7D%7D

1. 输入秘钥和系统参数,经过32轮迭代运算后,得到32个轮秘钥,每个秘钥32bit;

2. 输入密文和轮秘钥经过32轮迭代运算,每轮迭代需要一个轮密码,得到中间密文;

3. 将上述中间密文反转后得到最终密文;

 加密迭代过程如下:

​​​​​                        eq?X_%7Bi+4%7D%20%3DF%28X_%7Bi%7D%2CX_%7Bi+1%7D%2CX_%7Bi+2%7D%2CX_%7Bi+3%7D%2Crk_%7Bi%7D%29%2C%20i%3D0%2C1%2C%2C%2C31

其中rki是第一步128bit秘钥经过32轮迭代后生成的32个轮秘钥。那这些轮秘钥生成方式和加解迭代函数F具体形式是啥呢?往下看:

轮秘钥生成方式:

2cc959837cb6456a94baa2180e548742.png

输入的128bit密钥按每32bit划分为MK0,MK1,MK2,MK3,FK0,FK1,FK2,FK3是固定已知的参数,其中 FK0=A3B1BAC6,FK1=56AA3350,FK2=6777D9197,FK3=B27022DC;输入的秘钥和固定参数异或后得到初始值K0,K1,K2,K3,然后再经过32轮迭代;参数Ki是固定已知的,如下图所示:

6c3640c03e72496ebfee3031d616c0e2.png

迭代函数T`是非线性的,表达式如下:

       eq?T%28B%29%3DL%7B%7D%27%28%5Ctau%20%28B%29%20%29 ,其中eq?L%7B%7D%27%28B%29%3DB%5Cbigoplus%20%28B%3C%3C%3C13%29%5Cbigoplus%20%28B%3C%3C%3C23%29  <<<是循环移位,

T(B)是一个查找表,表格如下:

3c6557899f0c4038bed1d4cfc0288844.png

b722de10ab3c459b9686d9702e8eefc4.png

查找表介绍:这个查找表是一个非线性函数,XY的交叉点就是输出值,例如,X=C,Y=3,那输出值是92,,因为T函数的输入是32bit,而查找表是基于8bit的,所以需要将T函数的32bit输入划分为4个byte,每个byte经过查找表后结果再拼起来得到一个32bit输出,然后再经过函数L的逻辑运算;

举个例子:B=1A02344C, T(B) = 13E9C9E6

经过上述操作,我们可以得到32个轮密钥

加密迭代计算:

 

                eq?X_%7Bi&plus;4%7D%3DX_%7Bi%7D%5Coplus%20T%28X_%7Bi&plus;1%7D%5Cbigotimes%20X_%7Bi&plus;2%7D%5Coplus%20X_%7Bi&plus;3%7D%5Coplus%20rk_%7Bi%7D%29   eq?i%3D0%2C1%2C2..31

其中   eq?T%28B%29%3DL%7B%7D%28%5Ctau%20%28B%29%20%29 ,其中eq?L%7B%7D%28B%29%3DB%5Cbigoplus%20%28B%3C%3C%3C2%29%5Cbigoplus%20%28B%3C%3C%3C10%29%5Coplus%20%28B%3C%3C%3C18%29%5Coplus%20%28B%3C%3C%3C24%29 

其中T(B)是和轮密钥生成一样的查找表。

经过32轮迭代后,可以得到X32,X33,X34,X35

密文反转:        

        输出密文为:Y=(X35,X34,X33,X32)

下面图片展示了第一轮迭代过程,密钥的迭代结构是一样的,唯一区别是L(B) 替换为L`(B)

581f84839fc4423ab8552afb0c5ba747.jpeg

三:算法python代码

代码阅读完成后还是建议大家自己亲自手写一遍,加强对算法和python语法的熟悉

说明:加密数据和key是16进制的字符串输入;大家在抄写查找表一定要细心,这里面是一个坑;相比于SM3,这个算法Python实现起来更简单。这里面数据运算一般是基于32bit,也就是4个16进制数。

  1. class Sm4Algorithm:
  2. FK = ['a3b1bac6', '56aa3350', '677d9197', 'b27022dc']
  3. CK = ['00070e15', '1c232a31', '383f464d', '545b6269',
  4. '70777e85', '8c939aa1', 'a8afb6bd', 'c4cbd2d9',
  5. 'e0e7eef5', 'fc030a11', '181f262d', '343b4249',
  6. '50575e65', '6c737a81', '888f969d', 'a4abb2b9',
  7. 'c0c7ced5', 'dce3eaf1', 'f8ff060d', '141b2229',
  8. '30373e45', '4c535a61', '686f767d', '848b9299',
  9. 'a0a7aeb5', 'bcc3cad1', 'd8dfe6ed', 'f4fb0209',
  10. '10171e25', '2c333a41', '484f565d', '646b7279']
  11. TABLE = {'00': 'd6', '01': '90', '02': 'e9', '03': 'fe', '04': 'cc', '05': 'e1', '06': '3d', '07': 'b7',
  12. '08': '16', '09': 'b6', '0a': '14', '0b': 'c2', '0c': '28', '0d': 'fb', '0e': '2c', '0f': '05',
  13. '10': '2b', '11': '67', '12': '9a', '13': '76', '14': '2a', '15': 'be', '16': '04', '17': 'c3',
  14. '18': 'aa', '19': '44', '1a': '13', '1b': '26', '1c': '49', '1d': '86', '1e': '06', '1f': '99',
  15. '20': '9c', '21': '42', '22': '50', '23': 'f4', '24': '91', '25': 'ef', '26': '98', '27': '7a',
  16. '28': '33', '29': '54', '2a': '0b', '2b': '43', '2c': 'ed', '2d': 'cf', '2e': 'ac', '2f': '62',
  17. '30': 'e4', '31': 'b3', '32': '1c', '33': 'a9', '34': 'c9', '35': '08', '36': 'e8', '37': '95',
  18. '38': '80', '39': 'df', '3a': '94', '3b': 'fa', '3c': '75', '3d': '8f', '3e': '3f', '3f': 'a6',
  19. '40': '47', '41': '07', '42': 'a7', '43': 'fc', '44': 'f3', '45': '73', '46': '17', '47': 'ba',
  20. '48': '83', '49': '59', '4a': '3c', '4b': '19', '4c': 'e6', '4d': '85', '4e': '4f', '4f': 'a8',
  21. '50': '68', '51': '6b', '52': '81', '53': 'b2', '54': '71', '55': '64', '56': 'da', '57': '8b',
  22. '58': 'f8', '59': 'eb', '5a': '0f', '5b': '4b', '5c': '70', '5d': '56', '5e': '9d', '5f': '35',
  23. '60': '1e', '61': '24', '62': '0e', '63': '5e', '64': '63', '65': '58', '66': 'd1', '67': 'a2',
  24. '68': '25', '69': '22', '6a': '7c', '6b': '3b', '6c': '01', '6d': '21', '6e': '78', '6f': '87',
  25. '70': 'd4', '71': '00', '72': '46', '73': '57', '74': '9f', '75': 'd3', '76': '27', '77': '52',
  26. '78': '4c', '79': '36', '7a': '02', '7b': 'e7', '7c': 'a0', '7d': 'c4', '7e': 'c8', '7f': '9e',
  27. '80': 'ea', '81': 'bf', '82': '8a', '83': 'd2', '84': '40', '85': 'c7', '86': '38', '87': 'b5',
  28. '88': 'a3', '89': 'f7', '8a': 'f2', '8b': 'ce', '8c': 'f9', '8d': '61', '8e': '15', '8f': 'a1',
  29. '90': 'e0', '91': 'ae', '92': '5d', '93': 'a4', '94': '9b', '95': '34', '96': '1a', '97': '55',
  30. '98': 'ad', '99': '93', '9a': '32', '9b': '30', '9c': 'f5', '9d': '8c', '9e': 'b1', '9f': 'e3',
  31. 'a0': '1d', 'a1': 'f6', 'a2': 'e2', 'a3': '2e', 'a4': '82', 'a5': '66', 'a6': 'ca', 'a7': '60',
  32. 'a8': 'c0', 'a9': '29', 'aa': '23', 'ab': 'ab', 'ac': '0d', 'ad': '53', 'ae': '4e', 'af': '6f',
  33. 'b0': 'd5', 'b1': 'db', 'b2': '37', 'b3': '45', 'b4': 'de', 'b5': 'fd', 'b6': '8e', 'b7': '2f',
  34. 'b8': '03', 'b9': 'ff', 'ba': '6a', 'bb': '72', 'bc': '6d', 'bd': '6c', 'be': '5b', 'bf': '51',
  35. 'c0': '8d', 'c1': '1b', 'c2': 'af', 'c3': '92', 'c4': 'bb', 'c5': 'dd', 'c6': 'bc', 'c7': '7f',
  36. 'c8': '11', 'c9': 'd9', 'ca': '5c', 'cb': '41', 'cc': '1f', 'cd': '10', 'ce': '5a', 'cf': 'd8',
  37. 'd0': '0a', 'd1': 'c1', 'd2': '31', 'd3': '88', 'd4': 'a5', 'd5': 'cd', 'd6': '7b', 'd7': 'bd',
  38. 'd8': '2d', 'd9': '74', 'da': 'd0', 'db': '12', 'dc': 'b8', 'dd': 'e5', 'de': 'b4', 'df': 'b0',
  39. 'e0': '89', 'e1': '69', 'e2': '97', 'e3': '4a', 'e4': '0c', 'e5': '96', 'e6': '77', 'e7': '7e',
  40. 'e8': '65', 'e9': 'b9', 'ea': 'f1', 'eb': '09', 'ec': 'c5', 'ed': '6e', 'ee': 'c6', 'ef': '84',
  41. 'f0': '18', 'f1': 'f0', 'f2': '7d', 'f3': 'ec', 'f4': '3a', 'f5': 'dc', 'f6': '4d', 'f7': '20',
  42. 'f8': '79', 'f9': 'ee', 'fa': '5f', 'fb': '3e', 'fc': 'd7', 'fd': 'cb', 'fe': '39', 'ff': '48'}
  43. def x_box(self, x):
  44. x_str = '{:08x}'.format(x)
  45. y_str = ''
  46. for i in range(4):
  47. y_str = y_str + self.TABLE[x_str[i*2:i*2+2]]
  48. return int(y_str, 16) & 0xFFFFFFFF
  49. def rotate_left(self, a, k):
  50. k = k % 32
  51. return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32-k))
  52. def l_of_plaintext(self, x):
  53. return (x ^ self.rotate_left(x,2) ^ self.rotate_left(x,10) ^ self.rotate_left(x,18) ^self.rotate_left(x,24)) & 0xFFFFFFFF
  54. def l_of_key(self, x):
  55. return (x ^ self.rotate_left(x,13) ^ self.rotate_left(x,23)) & 0xFFFFFFFF
  56. def t_of_plaintext(self,x):
  57. return self.l_of_plaintext(self.x_box(x))
  58. def t_of_key(self, x):
  59. return self.l_of_key(self.x_box(x))
  60. def key_output(self, key):
  61. mk0 = int(key[8*0:8*1], 16) & 0xFFFFFFFF
  62. mk1 = int(key[8*1:8*2], 16) & 0xFFFFFFFF
  63. mk2 = int(key[8*2:8*3], 16) & 0xFFFFFFFF
  64. mk3 = int(key[8*3:8*4], 16) & 0xFFFFFFFF
  65. k0 = mk0 ^ (int(self.FK[0], 16) & 0xFFFFFFFF)
  66. k1 = mk1 ^ (int(self.FK[1], 16) & 0xFFFFFFFF)
  67. k2 = mk2 ^ (int(self.FK[2], 16) & 0xFFFFFFFF)
  68. k3 = mk3 ^ (int(self.FK[3], 16) & 0xFFFFFFFF)
  69. k = [0] * 36
  70. k[0:4] = [k0, k1, k2, k3]
  71. rk = [0] * 32
  72. for i in range(32):
  73. tmp = k[i+1] ^ k[i+2] ^ k[i+3] ^ (int(self.CK[i], 16) & 0xFFFFFFFF)
  74. k[i+4] = k[i] ^ self.t_of_key(tmp)
  75. # print(i,hex(k[i+4]))
  76. rk[i] = k[i+4]
  77. return rk
  78. def encryption(self, x, key):
  79. ciphertext = [0] * 36
  80. ciphertext[0] = int(x[8*0:8*1], 16) & 0xFFFFFFFF
  81. ciphertext[1] = int(x[8*1:8*2], 16) & 0xFFFFFFFF
  82. ciphertext[2] = int(x[8*2:8*3], 16) & 0xFFFFFFFF
  83. ciphertext[3] = int(x[8*3:8*4], 16) & 0xFFFFFFFF
  84. get_key = key
  85. rk = self.key_output(get_key)
  86. for i in range(32):
  87. tmp = ciphertext[i+1] ^ ciphertext[i+2] ^ ciphertext[i+3] ^ rk[i]
  88. ciphertext[i+4] = ciphertext[i] ^ self.t_of_plaintext(tmp)
  89. # print(i+4,hex(ciphertext[i+4]))
  90. y = '{:08x}'.format(ciphertext[35]) + '{:08x}'.format(ciphertext[34]) + '{:08x}'.format(ciphertext[33]) + '{:08x}'.format(ciphertext[32])
  91. return y
  92. if __name__ == '__main__':
  93. get_class = Sm4Algorithm()
  94. # case 1
  95. date = get_class.encryption('0123456789abcdeffedcba9876543210', '0123456789abcdeffedcba9876543210') # case1
  96. print(date)
  97. print(type(date))
  98. # case 2
  99. for i in range(1000000):
  100. if i == 0 :
  101. data = '0123456789abcdeffedcba9876543210'
  102. output = get_class.encryption(data, '0123456789abcdeffedcba9876543210')
  103. else :
  104. tmp = output
  105. output= get_class.encryption(tmp, '0123456789abcdeffedcba9876543210')
  106. if i == 999999:
  107. print(output)

四:Verilog硬件实现

“后续待补充”

 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/809814
推荐阅读
相关标签
  

闽ICP备14008679号