AES加密以及代码实现

AES加密回顾以及代码实现

Rijndael_Animation_v4_eng-html5

这里放了一个动态演示AES加密过程的网站,有兴趣的可以观看,建议挂代理食用

Rcon是轮常量:对称加密与非对称加密算法原理详解(对称加密篇) - 知乎

前言

接触密码学也两个月了,之前是学过AES的但是都是简单看了下大概,打CTF的时候喜欢python库脚本一把梭,对AES涉及的一些数学原理不理解,希望尝试用python实现AES加密。

重要的前置知识,有限域多项式乘法运算。

1.GF(28)中的多项式

伽罗瓦域之前以及了解过,大家有兴趣可以自己搜一下

$f(x)=a_7x^7+a_6x^6+…+a_1x^1+a_2x^2$

其中ai是x=2的系数=只能为1或者0,该多项式可以表示一个二进制整数

2.不可约的多项式规

$m(X)=x^8+x^4+x^3+x+1$

称之为不可约多项式,也就是质数

多项式模运算

接下来估计又是长篇大论了。多项式模运算我可以写的详细点

多项式运算分为三种

  • 使用代数方法运算的普通多项式

  • 系数运算是模P的多项式,即再系数GF(p)中

  • 系数在GF(p)中,且多项式被定义为模一个n次多项式m(x)的多项式运算

我们乘法逆元要用到第三章,然后正常运算后对M(X)取余数,才是最终运算结果。

例如f(x)=x6+x3++1与g(x)=x5+x4+x3相加

f(x)+g(x)=x5+x4+1,和异或一样。作乘法时

f(x)*g(x)=

讲一下多项式有限域相乘。先进行正常的代数相乘

得到,记得相加的时候是异或相加f(x)*g(x)=x11+x10+x9+x8+x7+x6+x5+x4+x3 mod(m(x))

x11=x3*x8—>多项式异或x3m(x)=x11+x7+x6+x4+x3

f(x)=x10+x9+x10+x9+x8+x5再异或x2m(x)=x10+x6+x5+x3+x2

得到f(x)=x9+x6+x3+x2异或相加xm(x)和m(x)求出结果

f(x)=x7+x6+x5+x4+x2+x

GF(28)还定义了运算,称为x乘法,其定义为

x*b(x)=b7x8+b6x7+…+b0x(mod m(x))

如果b7=0,求模结果不变,否则乘积减去m(x),即求乘积的结果与m(x)异或。

由此的得出十六进制02乘b(x)相当于在字节上左移一位(最后一位补0),若b7=1,则再与1B(00011011)做逐比特异或来实现,该运算记为b=xtime(a)

上述运算将会应用在列混淆之中

接下来示例57(16进制)在该条件下乘02

57=01010111,02=00000010相当于,第7位小于0,57左移一位后面补0。57=10101110=AE

如果是57*03可以看作57*(01+02)

如果AE*02,因为AE=10101110,先将AE左移一位补0

01011100*02 mod(00011011),这些都是为了满足有限域内的条件,具体数学原理,我也不太明白

1. AES加密

首先我们要知道,AES本身只能处理128位(16字节)的明文。在处理时将其按字节分成16块,4*4

A E I N
B F J O
C G K P
D H M Q

如果少了则填充0A。多了则重新排在另一个4*4的表格。

AES支持三种长度的密钥:128位,192位,256位

128位经历10轮,之后两种多64位增加两轮。

可以看出,AES加密有三个过程。初始轮,中间轮,最后轮。中间轮的数量在128Bites密钥中有

基础的四个过程。

  1. 字节替换(SubBytes) q

依据一个被称为S盒(Subtitution Box)的16*16大小的二维常量数组。示例如图。

如果我们要替换4d字节,那么我们就找到第4行,第d列即为e3。

  1. 行位移(ShiftRows)

    第一行不变,第二行左移一个字节,第三行左移三个字节,第四行左移四个字节。

    A E I N
    O B F J
    K P C G
    H M Q D
    1. 列混淆(MixColumns)。

    img

    用给定的一段矩阵左乘我们的数据,但是不完全跟矩阵乘法相同,示例结果如下,左乘的数

    例如第一行第一列,得到的结果是
    $$
    q1=(02p1)⊕(03p2)⊕(01p3)⊕(01p4)
    $$
    ⊕是异或(^)的意思。

    1. 轮密钥加(AddRoundKey)

    用明文矩阵和给定的轮密钥每一列进行异或。

例如如同。

这个密钥矩阵每轮都会改变。关于每轮的密钥扩展,

  • 每一轮都会生成一个新的轮密钥

初始轮密钥为a0/1/2/3.第i列的数据。

i!=4n时。 **ai=a[i-4] ^ a[i-1]**。

当i=4n时。 a[i]=a[i-4]^T(a[i-1])

T(a[i-1])需要做出解释。

分为三步。例如a4=a0^T(a[3])

  1. b3=[09,cf,4f,3c]左移一位<<得a3=[cf,4f,3c,09]

  2. 字节代换

    根据S盒。c3=[8a,84,eb,01]

  3. 将前两步的结果同轮常量Rcon[j],j表示轮数,

Rcon[j]是一个给定的4*j的表。

d3=b3^c3^rj

就能得到T(a[3])=d3

AES加密的不同模式

AES加密算法的模式主要有五种,主要区别在于加密过程中明文和密文的处理方式以及安全性特

1.ECB模式

  1. 每个明文块被独立加密,相同的明文块得到相同的密文块。
  2. 不适合加密大量数据或具有重复模式的数据,容易受到攻击。
  1. CBC模式
  1. 使用前一个密文块对当前明文块进行加密,增加了随机性,相同的明文块在不同位置得到

  2. 需要使用初始化向量(IV)来增加安全性。

  1. CFB模式。
  • 使用前一个密文块作为输入生成伪随机密钥流与明文进行异或运算得到密文。
  • 可以支持实时加密和流加密。
  1. OFB模式
  • 类似于CFB,使用前一个密文块生成伪随机密钥流,然后与明文进行异或运算。
  • 对加密和解密中的错误更加鲁棒,但不支持部分更新。
  1. CTR模式
  • 使用一个计数器与密钥输入加密算法生成伪随机密钥流,与明文进行异或运算。
  • 可以并行加密和解密,适用于需要高效加密的场景。

代码示例

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
import copy
def mul(poly1, poly2): # 两个多项式相乘
result = 0
for index in range(poly2.bit_length()):
if poly2 & (1 << index):
result ^= (poly1 << index)
return result

def mod(poly, mod = 0b100011011): # 多项式poly模多项式100011011
while poly.bit_length() > 8:
poly ^= (mod << (poly.bit_length() - 9))
return poly

def substitute(m_hex, inverse=False):
m_s = []
box = s_box if not inverse else i_s_box
for i in m_hex:
x, y = int(i, 16) // 16, int(i, 16) % 16
temp = hex(box[x*16+y])
m_s.append(temp)
return m_s

s_box = [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]
i_s_box = [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, 0x0E, 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]
rcon = [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]
mix_column_matrix = [0x2, 0x3, 0x1, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x2] # 列混合乘的矩阵
i_mix_column_matrix = [0xe, 0xb, 0xd, 0x9, 0x9, 0xe, 0xb, 0xd, 0xd, 0x9, 0xe, 0xb, 0xb, 0xd, 0x9, 0xe] # 列混合乘的逆矩阵
def gen_key(key):
key_hex = get_hex(key)
key_rotate = []
w = [[] for i in range(0, 44)]
for i in range(0, 16):
w[i // 4].append(key_hex[i])
for i in range(4, 44):
gw = copy.deepcopy(w[i - 1])
if i % 4 == 0:
gw[0], gw[1], gw[2], gw[3] = gw[1], gw[2], gw[3], gw[0]
gw = substitute(gw) #g(w(i-1))
gw[0] = hex(int(gw[0], 16) ^ rcon[i // 4 - 1]) #ppt上说的2^(i-4)/4有误,看书p84
for j in range(0, 4):
w[i].append(hex(int(gw[j], 16) ^ int(w[i-4][j], 16)))
key_rotate = [w[i * 4] + w[i * 4 + 1] + w[i * 4 + 2] + w[ i* 4 + 3] for i in range(0, 11)] # 轮密钥列表,每个元素都是有16个字节的列表
return key_rotate

def xor(a, key): #a和key都是列表,都存了16字节
return [hex(int(a[i], 16) ^ int(key[i], 16)) for i in range(0, 16)]

def get_hex(s): #得到一个字符串的十六进制值,以列表形式返回
return [hex(ord(i)) for i in s]

def shiftrows(a, inverse=False): #inverse为True时表示为逆操作,默认为False
return [ a[0], a[5], a[10], a[15], a[4], a[9], a[14], a[3], a[8], a[13], a[2], a[7], a[12], a[1], a[6], a[11] ] if not inverse else [ a[0], a[13], a[10], a[7], a[4], a[1], a[14], a[11], a[8], a[5], a[2], a[15], a[12], a[9], a[6], a[3] ]

def mixcolumn(m_row, inverse=False):
matrix = mix_column_matrix if not inverse else i_mix_column_matrix
m_col = []
for i in range(0, 16):
x, y = i % 4, i // 4
result = 0
for j in range(0, 4):
result ^= (mul(matrix[x * 4 + j], int(m_row[y * 4 + j], 16)))
result = mod(result)
m_col.append(hex(result))
return m_col

def aes_encrypt(m, key_rotate):
m_hex = get_hex(m) #得到明文的hex列表
m_xor = xor(m_hex, key_rotate[0]) #将明文初始xor密钥 w0 w1 w2 w3
for rotate in range(1, 11): #十轮
m_s = substitute(m_xor) # 字节代替
m_row = shiftrows(m_s)
m_col = m_row #列混合
if rotate != 10: #最后一轮不用列混合
m_col = mixcolumn(m_row)
m_xor = xor(m_col, key_rotate[rotate])
ciphertext = "" #输出的密文为每个十六进制字符的联结,类似e365e09962d634a8fbfe8359c57b22c5。一共32个,每两个字母对应了一个字节的十六进制。16个进制,128位。
for i in m_xor:
ciphertext += (i[2:] if len(i[2:]) == 2 else "0" + i[2:]) #对类似0xf的十六进制格式化为0x0f
return ciphertext

def aes_decrypt(c, key_rotate):
c_hex = ['0x' + c[i * 2] + c[i * 2 + 1] for i in range(0, 16)] #将密文恢复为列表
c_xor = xor(c_hex, key_rotate[10])
c_row = shiftrows(c_xor, inverse=True)
c_s = substitute(c_row, inverse=True)
for rotate in range(9, 0, -1): #循环9
c_xor = xor(c_s, key_rotate[rotate])
c_col = mixcolumn(c_xor, inverse=True)
c_row = shiftrows(c_col, inverse=True)
c_s = substitute(c_row, inverse=True)
plaintext = ""
for i in xor(c_s, key_rotate[0]): #将明文的hex列表转化为字母
plaintext += chr(int(i, 16))
return plaintext
# 原始明文和密钥
m = "1234567890abcdef"
key = "1234567890abcdef"

# 生成轮密钥
key_rotate = gen_key(key)

# 加密
ciphertext = aes_encrypt(m, key_rotate)
print("Ciphertext:", ciphertext)

# 解密
plaintext = aes_decrypt(ciphertext, key_rotate)
print("Decrypted text:", plaintext)

一道题

Knuckle Buster

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在这个挑战中,两个人 Alice 和 Bob 正在秘密交流。他们使用 Diffie-Hellman 密钥交换协议来保护他们的通信。我将为您提供足够的信息来解密他们之间截获的消息。您需要做的就是计算共享密钥并对其进行解密以获取标志。

这是加密的标志。它使用 AES-256-CBC 加密,其中 SHA-256 用于密钥派生,并预置了 16 字节 IV。

publicA
-----BEGIN PUBLIC KEY-----
MIGaMFMGCSqGSIb3DQEDATBGAkEAiBB/FlC3W8aPLJxYGXzKsnpEmPKIKR4JetlA1ky+TKTYofXUKSFucGxtrmWlVFjnLZUqJFjj0bVDKSiYOfod1wIBAgNDAAJAN3YrjXtIssyugO9tQ3BRy2TN92Qkhkp/VP5zfLEMQg1AE/YofkCIc/KSZOBpuroiQoCK0qTNkD4HzCzDa7ap5Q==
-----END PUBLIC KEY
-----
privateB
-----BEGIN PRIVATE KEY
-----MIGcAgEAMFMGCSqGSIb3DQEDATBGAkEAiBB/FlC3W8aPLJxYGXzKsnpEmPKIKR4JetlA1ky+TKTYofXUKSFucGxtrmWlVFjnLZUqJFjj0bVDKSiYOfod1wIBAgRCAkBSsgvp3xivPK6Wp2X+SIjGllg1MT4zJdEoyUjV6iDLGytdeLpokYOO6xss GIiVb8b6A/5onnopra2iXBb0dS5rn
-----END PRIVATE KEY
-----
dhparam
-----BEGIN DH 参数-----
MEYCQQCIEH8WULdbxo8snFgZfMqyekSY8ogpHgl62UDWTL5MpNih9dQpIW5wbG2uZaVUWOctlSokWOPRtUMpKJg5+h3XAgEC
-----END DH 参数
-----

这是一个基础的AES-CBC加密的DH密钥协商通信。

整数A,b和dhpraram=p分别代表了不同的内容。

P代表了DH中的那个大素数

协商密钥s=A^b^ modp。我们可以用python库或者在线网站提取证书内容,我这里直接用在线网站提取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import long_to_bytes
from nacl.hash import sha256

A=2904759796559791913432271862881153382405066619449245072640765589088056204557610156688164735437813811038059974077392278848266560053756599200768336365791717

b=4331114469004424101417452893702925534425506579657643668189751982919697469877978008431455296821274876511281317445036625437218508812066778389432224377969383

P=7126272917341517371021493195431918906260195973018916295547365059382419902222692924409321274266211448465008202837786841249505239162738008847348464904445399
s=pow(A,b,P)
key=sha256(long_to_bytes(s))
with open("C:\\Users\\24055\OneDrive\文档\Crypto200-1_flag.txt (1).enc","rb") as f:
iv=f.read(16)
cipher=f.read()
cipher1=cipher.hex()
print("IV:",iv.hex())
print("Cipher1:",cipher1)
print("Key:",key)#之后可以拿到在线网站解密即可
'''
IV: fe942f31b9579db8905e4202793cd70e
Cipher1: c206bd30b9339b208876fa125faac03f461db5cd6cf87ddf232ba7ff118d0d25
Key: b'bb7d44a422b90bb2b585c1639e46a7a7dff2cca315f564450694295d187b85d8'
'''
flag: poctf{uwsp_f1r3_4nd_br1m570n3}

SU_rsa

应该算是比较容易分析的简单rsa

由于给的是d的高位,直接可以用得到k(这算是一种整除,当时确实没想到这种方法,因为n和p,q,k差值过大所以k可以利用整除求出来)
$$
k=(ed_m-1)//n + 1
$$
由标准关系得到
$$
k
(n-p-q+1)+1==e*d\
(p+q) =(n+1+k^{-1})\mod e
$$
相当于给出了p%e或者q%e的值,e为256bits,显然small_roots求解一下就行。

值得注意的是,这里由于取的低位比较小,已知信息比较少,需要爆破

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
from Crypto.Util.number import *

d_m = 54846367460362174332079522877510670032871200032162046677317492493462931044216323394426650814743565762481796045534803612751698364585822047676578654787832771646295054609274740117061370718708622855577527177104905114099420613343527343145928755498638387667064228376160623881856439218281811203793522182599504560128
n = 102371500687797342407596664857291734254917985018214775746292433509077140372871717687125679767929573899320192533126974567980143105445007878861163511159294802350697707435107548927953839625147773016776671583898492755338444338394630801056367836711191009369960379855825277626760709076218114602209903833128735441623
e = 112238903025225752449505695131644979150784442753977451850362059850426421356123
k = (e*d_m-1)//n + 1
s = (n+1+inverse_mod(k, e))%e
PR.<x> = PolynomialRing(Zmod(e))
f = x^2-s*x+n
p0 = int(f.roots()[0][0])
print(p0)
import multiprocessing
import tqdm
from hashlib import sha256
def copper_attack(i):
PR.<x> = PolynomialRing(Zmod(n))
f = e*(2^12*x + i) + p0
f = f.monic()
res = f.small_roots(X=2^244, beta=0.499, epsilon=0.02)
if(res != []):
t = int(res[0])
p = e*(2^12*t + i) + p0
q = n // p
assert p * q == n and isPrime(p) and isPrime(q)
print(b'SUCTF{',sha256(str(p).encode()).hexdigest()[:32],b'}')
print(b'SUCTF{',sha256(str(q).encode()).hexdigest()[:32],b'}')
return True

with multiprocessing.Pool(processes=16) as pool:
for _ in tqdm.tqdm(pool.imap(copper_attack, range(2^12)), total=int(2^12)):
if(_):
break#多线程

AES加密以及代码实现
http://example.com/2024/12/24/AES加密回顾以及代码实现/
Beitragsautor
fox
Veröffentlicht am
December 24, 2024
Urheberrechtshinweis