首页 > 编程语言 >MD4(SHA-1,SM3)算法的实现

MD4(SHA-1,SM3)算法的实现

时间:2024-01-19 18:11:25浏览次数:26  
标签:16 32 self SM3 IV SHA num msg MD4

 

一、实验目的

深度理解MD4(SHA-1,SM3)算法的工作原理,理解单向散列函数的应用,体会区块链挖矿的难度系数、加深对单向散列函数性质的理解。

二、实验器材

pycharm+python3.11

三、实验内容

1.实验要求:自己配置python环境,编写MD4(SHA-1, SM3)算法实现程序,运行MD4(SHA-1,SM3)程序,演示MD4(SHA-1,SM3)算法的计算过程。

(1)编写程序实现任意消息的填充分组。

 1 flag = 1 # 补1标志位,补一次1后置0
 2 while len(M) % 512 != 448:
 3 if flag:
 4 M += '1'
 5 flag = 0
 6 else:
 7 M += '0'
 8 M += "{:064b}".format(l) # 末尾64位写入长度,空余补位补0
 9 M = hex(int(M, 2))[2:] # 这种转换会用到很多次,2进制转16进制,M现在是一个16进制字符串,如'1342a2c12...'
10 Mn = [] # 存储每个32位的字,因为M中一个字符4位(16进制),所以取M中的8个为一组,按要求将M分割成16个32位的字,故这里8*4=32,32*16=512
11 for i in range(16):
12 Mn.append(M[8*i: 8*i+8])

(2)编写程序实现消息扩展将每个分组中的16个32比特字扩展为80个32比特字。

 1 W = ['' for _ in range(80)] # 存储80份扩展子明文
 2 for i in range(80):
 3 if 16 <= i <= 79:
 4 # 16-79要进行异或运算,这里先转换成十进制(W中存的是16进制字符串,str无法运算)
 5 temp = int(W[i-3], 16) ^ int(W[i-8],
 6 16) ^ int(W[i-14], 16) ^ int(W[i-16], 16)
 7 
 8 W[i] = hex(roll_left(temp, 1))[2:].zfill(8) # 循环左移1位
 9 else:
10 W[i] = Mn[i]

(3)分别编写程序实现循环移位、32比特与(或、非)运算、模232加运算,建议将这些程序作为独立的程序,在整个运算中调用这些程序完成单向散列函数的计算。

def roll_left(num, k):
"""循环左移函数

Parameters
----------
num : int
输入一个数字,2进制、10进制等均可
k : int
左移位数

Returns
-------
int
返回一个int结果
"""
num_bin = bin(num)[2:].zfill(
32)
out = num_bin[k % len(num_bin):]+num_bin[:k % len(num_bin)] # 注意预防溢出
return int(out, 2) # 二进制左移完成后转化成10进制输出

def ft(b, c, d, t):
"""ft为逻辑函数

Parameters
----------
b : int
B值
c : int
C值
d : int
D值
t : int
轮次

Returns
-------
int
运算结果
"""
if t >= 0 and t <= 19:
return ((b & c) | (~b & d))
elif t >= 20 and t <= 39:
return (b ^ c ^ d)
elif t >= 40 and t <= 59:
return ((b & c) | (b & d) | (d & c))
elif t >= 60 and t <= 79:
return (b ^ c ^ d)

for t in range(80):
tmp = B
B = A
A = ((((E + ft(tmp, C, D, t)) % (2**32)+roll_left(A, 5)) %
(2**32)+int(W[t], 16)) % (2**32)+K[t//20]) % (2**32) # 预防溢出进行取模运算
E = D
D = C
C = roll_left(tmp, 30)

(4)用第二步的80个32比特字迭代修改初始的单向散列函数值,并输出最后的单向散列函数值。

SHA-1杂凑算法实现:

  1 A, B, C, D, E = 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 # 常量
  2 K = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6] # 常量
  3 
  4 str = input("输入明文:\n").encode('utf-8') # 这里对输入明文进行编码,str为bytes型
  5 l = len(str)*8 # 每个字符8位
  6 # python中二进制是字符串,不保留高位的0,这里使用zfill补高位0,如十进制6->110->0110,M这里是用了一个很长的字符串如:'11001010100011...'来表示原始数据
  7 M = bin(int(str.hex(), 16))[2:].zfill(l)
  8 
  9 # [可选项] 下面的函数仅仅显示输入明文的ascii,末尾为长度,该段显示的是补位后的
 10 for i in range(64):
 11 if i < len(str):
 12 print(str[i], end=' ')
 13 elif i < len(str)+1:
 14 print('128', end=' ')
 15 elif i < 63:
 16 print('0', end=' ')
 17 else:
 18 print(l)
 19 
 20 flag = 1 # 补1标志位,补一次1后置0
 21 while len(M) % 512 != 448:
 22 if flag:
 23 M += '1'
 24 flag = 0
 25 else:
 26 M += '0'
 27 M += "{:064b}".format(l) # 末尾64位写入长度,空余补位补0
 28 M = hex(int(M, 2))[2:] # 这种转换会用到很多次,2进制转16进制,M现在是一个16进制字符串,如'1342a2c12...'
 29 Mn = [] # 存储每个32位的字,因为M中一个字符4位(16进制),所以取M中的8个为一组,按要求将M分割成16个32位的字,故这里8*4=32,32*16=512
 30 for i in range(16):
 31 Mn.append(M[8*i: 8*i+8])
 32 
 33 
 34 def roll_left(num, k):
 35 """循环左移函数
 36 
 37 Parameters
 38 ----------
 39 num : int
 40 输入一个数字,2进制、10进制等均可
 41 k : int
 42 左移位数
 43 
 44 Returns
 45 -------
 46 int
 47 返回一个int结果
 48 """
 49 num_bin = bin(num)[2:].zfill(
 50 32)
 51 out = num_bin[k % len(num_bin):]+num_bin[:k % len(num_bin)] # 注意预防溢出
 52 return int(out, 2) # 二进制左移完成后转化成10进制输出
 53 
 54 
 55 W = ['' for _ in range(80)] # 存储80份扩展子明文
 56 for i in range(80):
 57 if 16 <= i <= 79:
 58 # 16-79要进行异或运算,这里先转换成十进制(W中存的是16进制字符串,str无法运算)
 59 temp = int(W[i-3], 16) ^ int(W[i-8],
 60 16) ^ int(W[i-14], 16) ^ int(W[i-16], 16)
 61 
 62 W[i] = hex(roll_left(temp, 1))[2:].zfill(8) # 循环左移1位
 63 else:
 64 W[i] = Mn[i]
 65 
 66 
 67 def ft(b, c, d, t):
 68 """ft为逻辑函数
 69 
 70 Parameters
 71 ----------
 72 b : int
 73 B值
 74 c : int
 75 C值
 76 d : int
 77 D值
 78 t : int
 79 轮次
 80 
 81 Returns
 82 -------
 83 int
 84 运算结果
 85 """
 86 if t >= 0 and t <= 19:
 87 return ((b & c) | (~b & d))
 88 elif t >= 20 and t <= 39:
 89 return (b ^ c ^ d)
 90 elif t >= 40 and t <= 59:
 91 return ((b & c) | (b & d) | (d & c))
 92 elif t >= 60 and t <= 79:
 93 return (b ^ c ^ d)
 94 
 95 
 96 Ap, Bp, Cp, Dp, Ep = A, B, C, D, E # 暂存初始值
 97 for t in range(80):
 98 tmp = B
 99 B = A
100 A = ((((E + ft(tmp, C, D, t)) % (2**32)+roll_left(A, 5)) %
101 (2**32)+int(W[t], 16)) % (2**32)+K[t//20]) % (2**32) # 预防溢出进行取模运算
102 E = D
103 D = C
104 C = roll_left(tmp, 30)
105 
106 #print(f" round{t+1} : {hex(A)} {hex(B)} {hex(C)} {hex(D)} {hex(E)}\n")
107 A, B, C, D, E = (Ap+A) % (2**32), (Bp+B) % (2**32), (Cp +
108 C) % (2**32), (Dp+D) % (2**32), (Ep+E) % (2**32)
109 # 相加运算,因为python不像c/c++可以使用unsigned char_32直接限制位数,因此要对位数进行限制
110 print("明文对应的杂凑码:\n", hex(A), hex(B), hex(C), hex(D), hex(E))

加密结果:

SM-3杂凑算法实现:

  1 def rotation_left(x, num):
  2 # 循环左移
  3 num %= 32
  4 left = (x << num) % (2 ** 32)
  5 right = (x >> (32 - num)) % (2 ** 32)
  6 result = left ^ right
  7 return result
  8 
  9 
 10 def Int2Bin(x, k):
 11 x = str(bin(x)[2:])
 12 result = "0" * (k - len(x)) + x
 13 return result
 14 
 15 class SM3:
 16 
 17 def __init__(self):
 18 # 常量初始化
 19 self.IV = [0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E]
 20 self.T = [0x79cc4519, 0x7a879d8a]
 21 self.maxu32 = 2 ** 32
 22 self.w1 = [0] * 68
 23 self.w2 = [0] * 64
 24 
 25 def ff(self, x, y, z, j):
 26 # 布尔函数FF
 27 result = 0
 28 if j < 16:
 29 result = x ^ y ^ z
 30 elif j >= 16:
 31 result = (x & y) | (x & z) | (y & z)
 32 return result
 33 
 34 def gg(self, x, y, z, j):
 35 # 布尔函数GG
 36 result = 0
 37 if j < 16:
 38 result = x ^ y ^ z
 39 elif j >= 16:
 40 result = (x & y) | (~x & z)
 41 return result
 42 
 43 def p(self, x, mode):
 44 result = 0
 45 # 置换函数P
 46 # 输入参数X的长度为32bit(=1个字)
 47 # 输入参数mode共两种取值:0和1
 48 if mode == 0:
 49 result = x ^ rotation_left(x, 9) ^ rotation_left(x, 17)
 50 elif mode == 1:
 51 result = x ^ rotation_left(x, 15) ^ rotation_left(x, 23)
 52 return result
 53 
 54 def sm3_fill(self, msg):
 55 # 填充消息,使其长度为512bit的整数倍
 56 # 输入参数msg为bytearray类型
 57 # 中间参数msg_new_bin为二进制string类型
 58 # 输出参数msg_new_bytes为bytearray类型
 59 length = len(msg) # msg的长度(单位:byte)
 60 l = length * 8 # msg的长度(单位:bit)
 61 
 62 num = length // 64
 63 remain_byte = length % 64
 64 msg_remain_bin = ""
 65 msg_new_bytes = bytearray((num + 1) * 64) ##填充后的消息长度,单位:byte
 66 
 67 # 将原数据存储至msg_new_bytes中
 68 for i in range(length):
 69 msg_new_bytes[i] = msg[i]
 70 
 71 # remain部分以二进制字符串形式存储
 72 remain_bit = remain_byte * 8 # 单位:bit
 73 for i in range(remain_byte):
 74 msg_remain_bin += "{:08b}".format(msg[num * 64 + i])
 75 
 76 k = (448 - l - 1) % 512
 77 while k < 0:
 78 # k为满足 l + k + 1 = 448 % 512 的最小非负整数
 79 k += 512
 80 
 81 msg_remain_bin += "1" + "0" * k + Int2Bin(l, 64)
 82 
 83 for i in range(0, 64 - remain_byte):
 84 str = msg_remain_bin[i * 8 + remain_bit: (i + 1) * 8 + remain_bit]
 85 temp = length + i
 86 msg_new_bytes[temp] = int(str, 2) # 将2进制字符串按byte为组转换为整数
 87 return msg_new_bytes
 88 
 89 def sm3_msg_extend(self, msg):
 90 # 扩展函数: 将512bit的数据msg扩展为132个字(w1共68个字,w2共64个字)
 91 # 输入参数msg为bytearray类型,长度为512bit=64byte
 92 for i in range(0, 16):
 93 self.w1[i] = int.from_bytes(msg[i * 4:(i + 1) * 4], byteorder="big")
 94 
 95 for i in range(16, 68):
 96 self.w1[i] = self.p(self.w1[i - 16] ^ self.w1[i - 9] ^ rotation_left(self.w1[i - 3], 15),
 97 1) ^ rotation_left(self.w1[i - 13], 7) ^ self.w1[i - 6]
 98 
 99 for i in range(64):
100 self.w2[i] = self.w1[i] ^ self.w1[i + 4]
101 
102 # 测试扩展数据w1和w2
103 # print("w1:")
104 # for i in range(0, len(self.w1), 8):
105 # print(hex(self.w1[i]))
106 # print("w2:")
107 # for i in range(0, len(self.w2), 8):
108 # print(hex(self.w2[i]))
109 
110 def sm3_compress(self, msg):
111 # 压缩函数
112 # 输入参数v为初始化参数,类型为bytes/bytearray,大小为256bit
113 # 输入参数msg为512bit的待压缩数据
114 
115 self.sm3_msg_extend(msg)
116 ss1 = 0
117 
118 A = self.IV[0]
119 B = self.IV[1]
120 C = self.IV[2]
121 D = self.IV[3]
122 E = self.IV[4]
123 F = self.IV[5]
124 G = self.IV[6]
125 H = self.IV[7]
126 
127 for j in range(64):
128 if j < 16:
129 ss1 = rotation_left((rotation_left(A, 12) + E + rotation_left(self.T[0], j)) % self.maxu32, 7)
130 elif j >= 16:
131 ss1 = rotation_left((rotation_left(A, 12) + E + rotation_left(self.T[1], j)) % self.maxu32, 7)
132 ss2 = ss1 ^ rotation_left(A, 12)
133 tt1 = (self.ff(A, B, C, j) + D + ss2 + self.w2[j]) % self.maxu32
134 tt2 = (self.gg(E, F, G, j) + H + ss1 + self.w1[j]) % self.maxu32
135 D = C
136 C = rotation_left(B, 9)
137 B = A
138 A = tt1
139 H = G
140 G = rotation_left(F, 19)
141 F = E
142 E = self.p(tt2, 0)
143 
144 # 测试IV的压缩中间值
145 # print("j= %d:" % j, hex(A)[2:], hex(B)[2:], hex(C)[2:], hex(D)[2:], hex(E)[2:], hex(F)[2:], hex(G)[2:], hex(H)[2:])
146 
147 self.IV[0] ^= A
148 self.IV[1] ^= B
149 self.IV[2] ^= C
150 self.IV[3] ^= D
151 self.IV[4] ^= E
152 self.IV[5] ^= F
153 self.IV[6] ^= G
154 self.IV[7] ^= H
155 
156 def sm3_update(self, msg):
157 # 迭代函数
158 # 输入参数msg为bytearray类型
159 # msg_new为bytearray类型
160 msg_new = self.sm3_fill(msg) # msg_new经过填充后一定是512的整数倍
161 n = len(msg_new) // 64 # n是整数,n>=1
162 
163 for i in range(0, n):
164 self.sm3_compress(msg_new[i * 64:(i + 1) * 64])
165 
166 def sm3_final(self):
167 digest_str = ""
168 for i in range(len(self.IV)):
169 digest_str += hex(self.IV[i])[2:]
170 
171 return digest_str.upper()
172 
173 def hashFile(self, filename):
174 with open(filename, 'rb') as fp:
175 contents = fp.read()
176 self.sm3_update(bytearray(contents))
177 return self.sm3_final()
178 
179 
180 if __name__ == "__main__":
181 msg1 = bytearray(b"abc")
182 print("msg1:", msg1.hex(), len(msg1))
183 
184 test1 = SM3()
185 test1.sm3_update(msg1)
186 digest1 = test1.sm3_final()
187 print("digest1:", digest1)
188 
189 msg2 = bytearray(b'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd')
190 msg2 = bytes(msg2)
191 print("msg2:", msg2.hex(), len(msg2))
192 
193 test2 = SM3()
194 test2.sm3_update(msg2)
195 digest2 = test2.sm3_final()
196 print("digest2:", digest2)
197 
198 # 求大小为48M的文件的摘要,大约需要7分钟
199 # test3 = SM3()
200 # file_digest = test3.hashFile("test.exe")
201 # print('file_digest', file_digest)

加密结果:

标签:16,32,self,SM3,IV,SHA,num,msg,MD4
From: https://www.cnblogs.com/doris510/p/17975300

相关文章

  • ShardingSphere-JDBC学习
    springBoot 引入maven<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.0.0-RC1<......
  • wireshark实践 - 调试spring连接mysql失败问题
    问题描述spring:datasource:driver-class-name:com.mysql.jdbc.Driverurl:jdbc:jdbc:mysql://122.224.147.xxx:90/dev?characterEncoding=utf8username:xxxpassword:xxxtype:com.alibaba.druid.pool.DruidDataSourceurl格式写错了(两个jdbc),然......
  • SM30里DEC数据显示0
    需求:DEC数据在维护的时候显示01,设置数据元素对于的域带转换历程、 2,写转换历程函数(注意两个历程的输入和输出类型,这个需要修改)FUNCTIONCONVERSION_EXIT_ZDAYS_INPUT.*"----------------------------------------------------------------------*"*"LocalInterface:*"......
  • Wireshark网络工具是什么?
    Wireshark是网络包分析工具。网络包分析工具的主要作用是尝试捕获网络包,并尝试显示包的尽可能详细的情况。Wireshark是一个免费开源软件,不需要付费,免费使用,可以直接登陆到Wireshark的官网下载安装。在windows环境中,Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,这个工具......
  • 玻尔兹曼-香农交互熵(Boltzmann–Shannon interaction entropy)及多尺度系列(Matlab版)
    玻尔兹曼-香农交互熵(Boltzmann–Shannoninteractionentropy)是2023年最新提出的一维时间序列的度量方式,在数据科学和机器学习领域有许多应用。(暂无任何文献应用报道)(matlab代码获取:https://mbd.pub/o/bread/mbd-ZZmclp1w)参考文献:https://doi.org/10.1063/5.0182349  ......
  • springboot~shardingsphere在非spring框架中的使用
    shardingsphere已经很方便的被springboot集成了,你只要引入sharding-jdbc-spring-boot-starter这个包就可以了,而如果是原生java的话,你就需要自己去实现了,主要是重新定义数据源,定义规则等问题,本文主要介绍原生环境下的shardingsphere的使用。依赖引用<dependencies><!--......
  • tcpdump+wireshark抓包分析
    目录tcpdump核心参数详解tcpdump的输出理解输出结构flag标识符常规过滤规则基于IP地址过滤基于网段过滤基于端口过滤基于协议进行过滤可选参数解析不解析域名提升速度结果输出到文件从文件中读取数据指定抓取个数指定设备口过滤规则组合tcpdump是linux下的一个命令行抓包工具wir......
  • c# csharp 对象序列化
    对象序列化要将一个序列化对象存储起来,您可以使用C#中的序列化和反序列化功能。以下是一个示例代码,它演示了如何将一个序列化对象存储到文件中:usingSystem;usingSystem.IO;usingSystem.Runtime.Serialization.Formatters.Binary;namespaceMyNamespace{[Serializab......
  • csharp c# http request get post put delete header respons json 网络请求
    C#中如何模拟一个post请求使用HttpClient代替。以下是修改后的代码示例:usingSystem;usingSystem.Net.Http;usingSystem.Text.Json;classHttpPostExample{privateasyncTask<string>HttpPost(stringUrl,objectpostData){stringpostDataStr=J......
  • PuppeteerSharp库在C#中的应用案例
    引言PuppeteerSharp是一个针对GoogleChrome浏览器的高级API库,它允许我们使用C#来控制Chrome浏览器的,比如模拟用户行为操作、爬取网页内容等。本文将介绍如何使用PuppeteerSharp库在C#中实现下载千图网图片并保存为PDF文件的案例。PuppeteerSharp技术PuppeteerSharp提供了一......