题目回顾
我们有以下题目描述和给定的数据:
1 | import gmpy2 |
理解题目
E和elist的生成:
E = 0x10000 = 65536
elist
是通过从E
开始,连续生成64个(0x41
)素数得到的列表。即elist = [next_prime(E), next_prime(next_prime(E)), ..., ]
共64个素数。
RSA参数:
p
和q
是1024位的素数。- 加密过程:
c = flag^elist[0] mod (p*q)
。即用elist
的第一个素数作为指数,模n=p*q
进行加密。
s列表的生成:
- 对于
elist
中的每个素数i
,计算:i - E
(表示为4位十六进制)p % i
(表示为4位十六进制)q % i
(表示为4位十六进制)
- 然后将这三个部分拼接成一个字符串,如
f"{i-E:04x}{p%i:04x}{q%i:04x}"
,存入s
列表。
- 对于
输出:
- 密文
c
。 - 列表
s
,其中每个元素是一个12位的十六进制字符串,可以拆分为三个4位的部分。
- 密文
目标
我们需要从给定的信息中恢复p
和q
,然后解密密文c
得到flag
。
解题步骤
第一步:解析s
列表
s
列表中的每个元素是一个12位的十六进制字符串,可以拆分为:
- 前4位:
i - E
- 中间4位:
p % i
- 最后4位:
q % i
因为E = 0x10000
,所以i = E + (i - E)
。因此,对于s
中的每个字符串,我们可以:
- 将字符串分成三个4位的部分:
delta
,p_mod
,q_mod
。 - 计算
i = E + int(delta, 16)
。 - 得到同余式:
p ≡ int(p_mod, 16) mod i
q ≡ int(q_mod, 16) mod i
第二步:收集同余式
对于s
中的每个元素,我们可以得到一个关于p
和q
的同余式。由于elist
中的i
都是素数,我们可以使用中国剩余定理(CRT)来恢复p
和q
模这些i
的乘积。
具体来说:
- 收集所有
i
和对应的p_mod
、q_mod
。 - 使用CRT求解
p
和q
模M = i1 * i2 * ... * i64
。- 由于
p
和q
都是1024位的数,而M
是64个大约16位(因为i
从E=65536
开始,next_prime
会稍微增加)的素数的乘积,M
的位数大约是64*16=1024
位,因此M
可能与p
或q
的大小相当或更大。 - 如果
M > p
和M > q
,那么通过CRT可以直接恢复p
和q
。
- 由于
第三步:恢复p
和q
- 从
s
中提取所有i
和p_mod
、q_mod
。 - 对
p
和q
分别应用CRT:p ≡ p_mod1 mod i1
p ≡ p_mod2 mod i2
- …
q ≡ q_mod1 mod i1
q ≡ q_mod2 mod i2
- …
- 使用
gmpy2
的crt
函数来求解p
和q
。
第四步:验证p
和q
由于p
和q
是1024位的素数,我们需要确保恢复的p
和q
确实是素数。如果M
足够大,恢复的p
和q
就是真实的p
和q
。
第五步:解密c
一旦有了p
和q
,可以计算n = p * q
和phi = (p-1)*(q-1)
。加密指数是e = elist[0]
,我们需要计算d = inverse(e, phi)
,然后计算m = pow(c, d, n)
,最后将m
转换为bytes
得到flag
。
实施步骤
1. 解析s
列表
1 | E = 0x10000 |
2. 使用CRT恢复p
和q
1 | import gmpy2 |
3. 计算n
和phi
,然后解密c
1 | n = p * q |
完整代码
1 | import gmpy2 |
可能的输出
如果一切顺利,运行上述代码将输出:
1 | p and q are primes! |
因为题目描述flag格式:bugku{},所以答案是 bugku{extend-extend-crt-1s-ea5y}
关于小学数学题的提示
题目中提到:“有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?”这是中国剩余定理(孙子定理)的经典例子。解为x ≡ 23 mod 105
。这提示我们在本题中需要使用中国剩余定理来恢复p
和q
。
总结
通过解析s
列表中的信息,我们可以恢复p
和q
模多个素数的余数,然后利用中国剩余定理恢复p
和q
本身。有了p
和q
后,就可以解密密文c
得到flag
。