RSA密码系统 是最常用的非对称密钥密码术之一,其安全性基于大整数质因子分解问题的困难性,即给定一个大整数,在短时间内将其分解为多个质因数的乘积在计算上是极其困难的。
在一个完整的通信过程中,其工作流程大致为:
接收者生成两个 大质数
�
,
�
p,q,计算
�
�
�
N=pq,同时生成公钥
�
�
�
�
{
�
,
�
}
k
pub
={e,N} 与私钥
�
�
�
�
{
�
,
�
}
k
pri
={d,N}。
接收者广播公钥
�
�
�
�
{
�
,
�
}
k
pub
={e,N}。
发送者使用公钥加密数据,得到密文
�
�
(
�
�
�
�
,
�
)
�
�
m
o
d
�
c=f(k
pub
,m)=m
e
modN。
发送者广播密文
�
c。
接收者使用私钥解密数据,得到明文
�
�
(
�
�
�
�
,
�
)
�
�
m
o
d
�
m=g(k
pri
,c)=c
d
modN。
其中的值满足以下性质:
�
<
�
m<N,
gcd
(
�
,
�
)
1
gcd(m,N)=1.
�
<
�
e<N,
gcd
(
�
,
�
)
1
gcd(e,N)=1.
�
�
≡
1
(
m
o
d
�
(
�
)
)
ed≡1(modφ(N)).
�
(
�
)
(
�
−
1
)
(
�
−
1
)
φ(N)=(p−1)(q−1).
如果明文
�
m 规模过大,可考虑将其分段发送。
现有某道 CTF 题目涉及此过程,而不幸的是你正好是 隔壁老王 题目涉及通信过程中的“非法第三者”。你希望获取通信内容
�
m,但现在你只知道
�
,
�
,
�
e,N,c 的值与关于
�
,
�
p,q 的一个性质:
∣
�
−
�
∣
≤
2
×
1
0
5
∣p−q∣≤2×10
5
。
希望你能根据以上信息与给定的
�
,
�
,
�
e,N,c 快速求出明文
�
m。
输入:一行
3
3 个整数,分别为
�
,
�
,
�
e,N,c 的值。
输出:一行
1
1 个整数,
�
m 的值。
样例输入:65537 293000179499792623 13189131411060906
样例输出:114514
数据范围:
1≤N≤10
18
。
1
≤
�
≤
�
,
gcd
(
�
,
�
)
1
1≤e≤N,gcd(e,N)=1。
0
≤
�
<
�
0≤C<N。
�
�
�
N=pq,其中
�
,
�
p,q 为质数,且
∣
�
−
�
∣
≤
2
×
1
0
5
∣p−q∣≤2×10
5
。
此外:你可能需要使用 扩展欧几里得算法 的相关结论在已知
�
,
�
(
�
)
e,φ(N) 的情况下求
�
d,下面将提供相关代码,求
�
d 时调用 d=mod_inverse(e,phi) 即可,其两个参数分别为
�
e 与
�
(
�
)
φ(N) 的值。
long long extended_gcd(long long a, long long b, long long *x, long long *y) {
if (a == 0) {
*x = 0;
*y = 1;
return b;
}
long long x1, y1, gcd = extended_gcd(b % a, a, &x1, &y1);
*x = y1 - (b / a) * x1;
*y = x1;
return gcd;
}
long long mod_inverse(long long e,long long phi) {
long long x, y, gcd = extended_gcd(e, phi, &x, &y);
if (gcd != 1)return -1;//表示错误,但本题数据保证不会有此情况
else {
x = (x % phi + phi) % phi;
return x;
}
}
你可能需要使用 快速幂算法 以高效地由
�
,
�
,
�
c,d,N 求出
�
m,下面将提供相关代码。
long long qmi(long long c,long long d,long long N){
long long res=1%N;
while(d){
if(d&1)res=(__int128)res*c%N;
c=(__int128)c*c%N;
d>>=1;
}
return res;
}
上述第二段代码中使用了数据类型 __int128,其是128位整型。截至2024年底,__int128 不是C/C++中的标准数据类型。但包括本平台在内的大多数编译器支持该类型。如编译器不支持,另可使用 龟速乘算法 替代,其在理论上其对本处的程序运行效率几乎没有影响。