应用密码学实验笔记

本文最后更新于 2024年11月29日 下午

应用密码学实验笔记

密码学数学基础

单元测试

有限域运算

  1. 关于x-time的计算(有限域为GF($2^8$)):

    • 在AES 算法中定义 m(x) 多项式(不可约多项式)为: m(x)=x8+x4+x3+x+1(十六进制的11B)

    x-time(x)就是计算x<<1(相当于乘2),如果移位前的最高位为1,就让移位后x取模m(x)一定要注意顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
unsigned char XTIME(unsigned char x)
{
//*******************Begin*******************
x <<= 1;
if(x & 0x80) x ^= 0x1b;
return x;
//*********************End********************
}

int main()
{
unsigned char a;
scanf("%x",&a);
printf("0x%x\n",XTIME(a));
return 0;
}

  1. 有限域的乘法计算

扩展欧几里得算法

贝祖等式:$s \cdot a + t \cdot b = (a,b)$;其中(a,b)为a、b的最大公因数。利用扩展欧几里得算法,根据贝祖等式,可以求乘法逆元。

一般用较大的数作为模

前提:

  • a、b互素才有乘法逆元

  • 把大的那一方当作b,当作模数,最终的s即为所求(个人理解)

    下图是一个手写的示例

    若从a=121,b=169开始,最上面补一步

    (左侧为a,右侧的除数为b)

    依次a1、b1

    121 = 0 * 169 + 121

手写图

169 mod 121的乘法逆元即为58。

$gcd(a,b)=sa+tb$

$gcd(a,b)=gcd(b,a%b)$是子式之间的关系

$sa+tb=s_1b+t_1(a-a//b*b)$

即$a_1=b,b_1=a-a//b$依次可以继续递推,直到欧几里得的倒数第二步(也就是图中的最后1步)

再下一步是1 = 0*0+1

$a_n=b_{n-1}=1,b_n=0$

则s=1,t=0

它的上一步的值就得知了。

并且由$sa+tb=s_1b+t_1(a-a//b*b)$化简得

$sa+tb = s_1b+t_1a-t1(a//b*b)$

则$s=t1,t=s1-t1(a//b)$

下列代码以b为较大的数,mod b,则最终的s即为所求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def gcd(a, b):
# *************begin************#

r = a % b
while r:
a = b
b = r
r = a % b
return b


# **************end*************#
def extendGcd(a, b):
#***********************Begin**************************
if b == 0:
return (1, 0)
s1 , t1 = extendGcd(b,a % b)
s = t1
t = s1 - t1 * (a // b)
return s,t


#*************************End**************************

def main():
a = int(input())
b = int(input())
if a > b:
temp = a
a = b
b = temp
if gcd(a, b)==1:
r = extendGcd(a, b)[0]%b
else:
r = None
print(r)


if __name__ == '__main__':
main()

c++实现(其实是用c,但是&的引用c不支持,c++才支持)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

long exEuclid(long a,long b,long &x,long &y)
{
/***********************Begin**************************/
if (b == 0)
{
x = 1;
y = 0;
return a;
}
long gcd = exEuclid(b, a % b, x, y);
long temp;
temp = x;
x = y;
y = temp - y * (a / b);
return gcd;
/*************************End**************************/
}


int main() {
long a, b, x, y = 0, t;
scanf("%ld %ld", &a, &b); //测试集输入a、b,要求exEuclid函数的输出与a、b输入的顺序无关
if (a > b) {
t = a;
a = b;
b = t;
}
printf("%ld %ld %ld", x, y, exEuclid(a, b, x, y));
//使得函数exEuclid返回gcd(a,b),依次输出x、y、gcd,使得等式a*x+b*y=gcd(a,b)
return 0;
}

中国剩余定理

按照公式计算即可。

$m=m_1\cdots m_k,\quad m=m_i\cdot M_i,\quad i=1,\cdots,k,$

$M_i^{\prime}\cdot M_i\equiv1\pmod{m_i}, i=1,2,\cdots,k.$

$x\equiv b_1\cdot M_1^{\prime}\cdot M_1+b_2\cdot M_2^{\prime}\cdot M_2+\cdots+b_k\cdot M_k^{\prime}\cdot M_k\pmod{m}$

其中,M_list分别对应各个M,M_n_list对应M的逆的列表。(题中ei_list对应M的逆,这里回顾一下列表生成式的使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- coding: UTF-8 -*-
def Get_Mi(m_list,M):
M_list=[]
for mi in m_list:
M_list.append(M//mi)
return M_list

def Get_ei_list(M_list,m_list):
ei_list=[]
for i in range(len(M_list)):
ei_list.append(Get_ei(M_list[i],m_list[i])[0])
return ei_list
def Get_ei(a,b):
# 计算ei,猜测为求M的逆元
# 请在此处添加代码 #
# *************begin************#
if b == 0:
return (1, 0)
s1 , t1 = Get_ei(b,a % b)
s = t1
t = s1 - t1 * (a // b)
return s,t

# **************end*************#
def crt(a_list, m_list):
# 计算中国剩余定理,返回计算结果
# 请在此处添加代码 #
# *************begin************#
m = 1
for i in m_list:
m *= i
M_list = Get_Mi(m_list, m)
# ei_list = Get_ei_list(M_list, m_list)
M_n_list = [Get_ei(a,b)[0]%b for a ,b in zip(M_list,m_list)]
return sum([b*M*M_n for b,M,M_n in zip(a_list,M_list,M_n_list)])% m



# **************end*************#
if __name__ == '__main__':
a_list = list(map(int, input().split(",")))
m_list = list(map(int, input().split(",")))
print(crt(a_list, m_list))

并发大素数计算

由于限制了运行时间,注意尽可能减少素数的判断,将偶数除去,并且获取CPU最大核心数作为并发数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from concurrent.futures import ProcessPoolExecutor
import math
import os
def is_prime(num):
if num <= 1:
return False
if num == 2:
return True
if num % 2 == 0:
return False
for i in range(3, int(math.sqrt(num)) + 1, 2):
if num % i == 0:
return False
return True

def main():
results = []
max_workers = os.cpu_count() # 获取 CPU 核心数作为最大并发数
with ProcessPoolExecutor(max_workers=max_workers) as executor:
for result in executor.map(is_prime, PRIMES):
results.append(result)

# 最后统一输出结果
for res in results:
print(res)

if __name__ == '__main__':
PRIMES = list(map(int, input().split(",")))
main()

python手搓AES-128

AES需要的步骤:扩展密钥,及10轮操作。前九轮操作为轮密钥加、字节代替、行移位、列混淆。最后一轮没有列混淆。

密钥扩展

​ 4个字(16字节)的密钥扩展为44个字的密钥。

​ 以下是伪代码(来自密码编码学域网络安全-原理与实践(第八版))

image-20241120170318310

​ 其中,subword是s盒变换,RotWord是行循环左移1位,Rcon是轮常量,Rcon[j] = [Rc[j],0,0,0]。RC[j]的初始值为1,后续是前一项乘2(注意,这里的乘法都是有限域上的乘法)

​ 注意,这里需要将输入的密钥以ascii码存储,用二维列表w[44] [4]来存储它们

  • 进行字符串的转化时的问题:

​ 当字节型数据与字符混合在一个字符串中时,单独提取的一个数据会被转化为整数,即字节型数据单独提取时会化为整数。

image-20241120193742293

  • 注意,RC在数组中时从0开始的,书上时从1开始的,调用数组时要减1

    1
    temp = [self.Sbox(a ^ b) for a, b in zip(self.Rotword(temp), [self.RC[i // 4 - 1], 0, 0, 0])]
  • 注意,在Rotword时,不要把原本的密钥的顺序移位了,创建一个新列表,深拷贝数据,然后再移位。

  • 在以4为倍数的密钥扩展时,是先把行移位的temp进行S盒变换,再进行异或。

  • 数据往4*4的矩阵是按列填充的。

  • 在一维列表(4*4)中,行列转置的方法:

1
2
text_t = [[text[i + j * 4] for j in range(4)] for i in range(4)]
text_t = [item for row in text_t for item in row]

第一行提取出列,并且生成二维矩阵,第二行将其扁平化为一维矩阵。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
from binascii import b2a_hex, a2b_hex
import copy


class aestest:
def __init__(self, key):
self.key = key
self.pad_len = 0
self.RC = [0x01] # 初始化为 GF(2^8) 的 1
for _ in range(9):
self.RC.append(self.gf_mul(self.RC[-1], 0x02)) # 每次乘以 x (0x02 在 GF(2^8) 表示 x)
self.exkey = self.key_extend()

def gf_mul(self, a, b, mod=0x11B):
"""
在有限域 GF(2^8) 中计算 a 和 b 的乘积。
参数:
a (int): 被乘数
b (int): 乘数
mod (int): 模多项式 (默认使用 0x11B,对应 AES 标准)
返回:
int: 乘积在 GF(2^8) 上的结果
"""
result = 0 # 初始化结果
while b > 0:
if b & 1:
result ^= a # XOR 累加
a <<= 1
if a & 0x100: # 检查第 9 位
a ^= mod # 模多项式约简

# 右移 b,处理下一位
b >>= 1
return result

def Rotword(self, w):
# 向左移动1位
w.append(w.pop(0))
return w

def key_extend(self):
"""
密钥扩展
:return:返回扩展密钥
"""
w = []
for i in range(0, 4):
words = self.key[i * 4:i * 4 + 4]
words_list = []

for char in words: # 针对直接输入16进制数的输入测试案例的转化
words_list.append(int(char))

w.append(words_list)
for i in range(4, 44):
temp = copy.deepcopy(w[i - 1])
if i % 4 == 0:
temp = [self.Sbox(a) ^ b for a, b in zip(self.Rotword(temp), [self.RC[i // 4 - 1], 0, 0, 0])]
w.append([a ^ b for a, b in zip(w[i - 4], temp)])
w_t = []

for m in range(11):
for i in range(4):
temp = [] # 注意位置,不能放在上面。否则会改变w_t中其他位置的值
for j in range(4):
temp.append(w[4 * m + j][i])
w_t.append(temp)

# for lists in w_t:
# for char in lists:
# print(f'{hex(char)} ',end='')
# print('')
return w_t

def Sbox(self, b):
sbox = (
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16)
return sbox[b]

def Sbox_inv(self, b):
sbox_inv = (
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0xe, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
)
return sbox_inv[b]

def Rowmovs(self, text):
#行移位
list1 = text[0:4]
list2 = text[4:8]
self.Rotword(list2)
list3 = text[8:12]
self.Rotword(list3)
self.Rotword(list3)
list4 = text[12:16]
list4.insert(0, list4.pop())
return list1 + list2 + list3 + list4

def Rowmovs_inv(self, text):
#逆向行移位
list1 = text[0:4]
list2 = text[4:8]
list2.insert(0, list2.pop())
list3 = text[8:12]
self.Rotword(list3)
self.Rotword(list3)
list4 = text[12:16]
self.Rotword(list4)
return list1 + list2 + list3 + list4

def Column_mix(self, text):
list_tool = [2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2] # 正向列混淆矩阵
result = []
for i in range(4):
for j in range(4):
temp0 = 0
for k in range(4):
# print(f"{hex(list_tool[k + 4 * i])}*{hex(text[j + 4 * k])}")
temp0 ^= self.gf_mul(list_tool[k + 4 * i], text[j + 4 * k])
# print(f"{hex(temp0)}")
result.append(temp0)
# for i in range(16):
# print(f"{hex(result[i])} ",end='')
return result

def Column_mix_inv(self, text):
list_tool = [0xe, 0xb, 0xd, 0x9, 0x9, 0xe, 0xb, 0xd, 0xd, 0x9, 0xe, 0xb, 0xb, 0xd, 0x9, 0xe]
result = []
for i in range(4):
for j in range(4):
temp0 = 0
for k in range(4):
# print(f"{hex(list_tool[k + 4 * i])}*{hex(text[j + 4 * k])}")
temp0 ^= self.gf_mul(list_tool[k + 4 * i], text[j + 4 * k])
# print(f"{hex(temp0)}")
result.append(temp0)
# for i in range(16):
# print(f"{hex(result[i])} ",end='')
return result

def pad(self, text):
# 填充函数,使明文长度为16字节的倍数,填充值是缺乏的长度,填充标准采用了PKCS#7
self.pad_len = (16 - len(text)) % 16
if self.pad_len != 0:
for _ in range(self.pad_len):
text.append(str(self.pad_len))

def unpad(self, text):
# 去填充函数
if self.pad_len != 0:
for _ in range(self.pad_len):
text.pop()

def encrypt(self, text):
self.pad(text)
#print(text)
# 初始轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = int(text[i * 4 + j]) ^ self.exkey[i][j]
for times in range(1, 10):
# S盒变换
for i in range(16):
# print(hex(text[i]))
text[i] = self.Sbox(text[i])
# print(hex(text[i]))
# 行移位
text = self.Rowmovs(text)
# for i in text:
# print(f"{hex(i)} ",end='')
# print()
# 列混淆
text = self.Column_mix(text)
# for i in text:
# print(f"{hex(i)} ", end='')
# print()
# 轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = text[i * 4 + j] ^ self.exkey[4 * times + i][j]
# 第10轮
# S盒变换
for i in range(16):
text[i] = self.Sbox(text[i])
# 行移位
text = self.Rowmovs(text)
# 轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = text[i * 4 + j] ^ self.exkey[40 + i][j]
text_t = [[text[i + j * 4] for j in range(4)] for i in range(4)]
text_t = [item for row in text_t for item in row]
hex_str = ''.join(format(x, '02x') for x in text_t).encode()
return hex_str

def decrypt(self, text_t):
self.unpad(text_t)
text = [[text_t[i + j * 4] for j in range(4)] for i in range(4)]
text = [item for row in text for item in row]
# 先执行一次轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = text[i * 4 + j] ^ self.exkey[40 + i][j]
# 逆向行移位
text = self.Rowmovs_inv(text)
# 逆S盒变换
for i in range(16):
text[i] = self.Sbox_inv(text[i])
for times in range(9, 0, -1):
# 轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = text[i * 4 + j] ^ self.exkey[4 * times + i][j]
# 逆向列混淆
text = self.Column_mix_inv(text)
# 逆向行移位
text = self.Rowmovs_inv(text)
# 逆S盒
for i in range(16):
text[i] = self.Sbox_inv(text[i])

# 最后的轮密钥加
for i in range(4):
for j in range(4):
text[i * 4 + j] = int(text[i * 4 + j]) ^ self.exkey[i][j]
# for i in range(16):
# print(f"{hex(text[i])} ",end='')
# print()
text_t = [[text[i + j * 4] for j in range(4)] for i in range(4)]
text_t = [item for row in text_t for item in row]
hex_str = ''.join(chr(x) for x in text_t).encode()
return hex_str


#************End***************

def Evidence(text, keys):
# 要求key长度为16
keys = [str(ord(a)) for a in keys]
text = [str(ord(a)) for a in text]
text_t = [[text[i + j * 4] for j in range(4)] for i in range(4)]
text_t = [item for row in text_t for item in row]
aes = aestest(keys)
enc = aes.encrypt(text_t)
print(enc)
detext = aes.decrypt([strs for strs in a2b_hex(enc)])
print(detext)


text, keys = input().split()
# 测试数据
# text = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]
# keys = [0xf, 0x15, 0x71, 0xc9, 0x47, 0xd9, 0xe8, 0x59, 0x0c, 0xb7, 0xad, 0xd6, 0xaf, 0x7f, 0x67, 0x98]
# 密文ff0b844a0853bf7c6934ab4364148fb9
Evidence(text, keys)

公钥密码算法

RSA算法

  • 快速幂乘法注意:
    • 首次乘乘数,其次每次都乘本身,不要混淆乘每次都乘乘数
    • 结果也是累的积
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#从底层实现RSA算法的加密和解密,要求加密和解密过程的求幂过程采用快速乘方算法
class rsatest():
def __init__(self,e,d,n):
self.e = e
self.d = d
self.n = n
def quick_pow(self,code,times):
times = bin(times)[2:]
factor = 1 # 乘数
flag = 1
result = 1
for i in range(len(times)-1, -1, -1):
if flag == 1:
flag = 0
factor = code
else:
factor = factor * factor
factor %= self.n
if times[i] == '1':
result *= factor
result %= self.n
return result



def encrypt(self,p):
return self.quick_pow(p, self.e)
def decrypt(self,enc):
return self.quick_pow(enc, self.d)

def Evidence(p,e,d,n):
"""
:param p: 明文
:param e: 公钥
:param d: 私钥
:param n: 模
"""
rsa = rsatest(e,d,n)
enc = rsa.encrypt(p)
print(enc)
detext = rsa.decrypt(enc)
print(detext)

if __name__ == "__main__":
str1, str2 ,str3,str4 = input().split()
p = int(str1)
e = int(str2)
d = int(str3)
n = int(str4)
Evidence(p,e,d,n)

调用模块生成RSA密钥,并执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import base64
from OpenSSL.crypto import PKey, TYPE_RSA, FILETYPE_PEM, dump_privatekey, dump_publickey
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP


def generate_rsa_keys():
# 创建 PKey 对象并生成 RSA 密钥
key = PKey()
key.generate_key(TYPE_RSA, 2048)

# 导出公私钥到 PEM 格式(字节串)
private_key_pem = dump_privatekey(FILETYPE_PEM, key)
public_key_pem = dump_publickey(FILETYPE_PEM, key)

# 将字节串转化为 PEM 格式的字符串,包含正确的标记
private_key_pem_str = private_key_pem.decode('utf-8')
public_key_pem_str = public_key_pem.decode('utf-8')

# 将 PEM 格式的密钥保存到文件
# with open("private_key.pem", "w") as private_file:
# private_file.write(private_key_pem_str)
#
# with open("public_key.pem", "w") as public_file:
# public_file.write(public_key_pem_str)

return private_key_pem_str, public_key_pem_str


def encrypt_text(public_key_pem_str, text):
# 使用 PyCrypto 加载公钥
public_key = RSA.importKey(public_key_pem_str.encode())

cipher = PKCS1_OAEP.new(public_key)

encrypted_text = cipher.encrypt(text.encode())
return base64.b64encode(encrypted_text).decode()


def decrypt_text(private_key_pem_str, encrypted_text):
# 使用 PyCrypto 加载私钥
private_key = RSA.importKey(private_key_pem_str.encode())
cipher = PKCS1_OAEP.new(private_key)

# 解密文本
encrypted_bytes = base64.b64decode(encrypted_text)
decrypted_text = cipher.decrypt(encrypted_bytes).decode()
return decrypted_text


def main(text):
private_pem, public_pem = generate_rsa_keys()
# 使用公钥加密文本
encrypted_text = encrypt_text(public_pem, text)
# print(f"Encrypted text: {encrypted_text}")

# 使用私钥解密文本
decrypted_text = decrypt_text(private_pem, encrypted_text)
print(decrypted_text)


if __name__ == '__main__':
text = input("Enter text to encrypt: ")

main(text)


应用密码学实验笔记
https://xyyr-c.github.io/2024/11/20/应用密码学实验笔记/
作者
xyyr
发布于
2024年11月20日
许可协议