RSA解密
友情链接:RSA解密
题目:
思路:
对于这道题目,给出了三个已知量n d C
,要我们进行解密,对于解密的公式
X
=
C
e
m
o
d
n
X = C^e \mod n
X=Cemodn来讲,我们有唯一的参数e
是未知的,因此问题就转化为了如何求解e
的值,对于求解e
的值,题目给出的有用条件:找到两个质数p
q
使其满足
d
=
p
⋅
q
d = p \cdot q
d=p⋅q 和
d
m
o
d
(
p
−
1
)
⋅
(
q
−
1
)
=
1
d \mod {(p - 1) \cdot (q - 1)} = 1
dmod(p−1)⋅(q−1)=1,即d
与(p - 1)·(q - 1)
互质,然后给出
(
d
⋅
e
)
m
o
d
(
(
p
−
1
)
⋅
(
q
−
1
)
)
=
1
(d\cdot e) \mod ((p - 1)\cdot (q - 1)) = 1
(d⋅e)mod((p−1)⋅(q−1))=1。使用更易懂的公式可表述为:
d
⋅
e
−
k
(
(
p
−
1
)
⋅
(
q
−
1
)
)
=
1
,(其中
k
是一个未知量)
d\cdot e - k((p - 1)\cdot (q - 1)) = 1,(其中k是一个未知量)
d⋅e−k((p−1)⋅(q−1))=1,(其中k是一个未知量),意思是:对于
d
⋅
e
d \cdot e
d⋅e,可以减去
k
k
k个
(
p
−
1
)
⋅
(
q
−
1
)
(p - 1)\cdot (q - 1)
(p−1)⋅(q−1),使得最后的差值为
1
1
1。
对公式 d ⋅ e − k ( ( p − 1 ) ⋅ ( q − 1 ) ) = 1 ,(其中 k 是一个未知量) d\cdot e - k((p - 1)\cdot (q - 1)) = 1,(其中k是一个未知量) d⋅e−k((p−1)⋅(q−1))=1,(其中k是一个未知量) 的理解:
举个例子:假设 d ⋅ e = 16 d \cdot e = 16 d⋅e=16而 ( p − 1 ) ⋅ ( q − 1 ) = 5 (p - 1)\cdot (q - 1) = 5 (p−1)⋅(q−1)=5,我们要求 ( d ⋅ e ) m o d ( ( p − 1 ) ⋅ ( q − 1 ) ) = 1 即 16 m o d 5 = 1 (d\cdot e) \mod ((p - 1)\cdot (q - 1)) = 1 ~~~ 即16 \mod 5 = 1 (d⋅e)mod((p−1)⋅(q−1))=1 即16mod5=1,这个意思是使
16
除以5
的余数为1
,因为除法和减法有着非常大的联系(除以一个数的值等于减去这个数的次数,余数等于相减之后的差值),因此我们可以从新将其写为 16 − k ⋅ 5 = 1 16 - k\cdot 5 = 1 16−k⋅5=1,即16
减去多少个5
后值为1
。
为了方便书写,我们设
φ
=
(
p
−
1
)
⋅
(
q
−
1
)
\varphi = (p - 1)\cdot(q - 1)
φ=(p−1)⋅(q−1),这样公式就又化简为了
d
⋅
e
−
k
φ
=
1
,(其中
k
是一个未知量)
d\cdot e - k\varphi = 1,(其中k是一个未知量)
d⋅e−kφ=1,(其中k是一个未知量),由于又涉及到了两个新的未知量
φ
\varphi
φ和
k
k
k,要想求出
e
e
e,我们需要提前求出
φ
\varphi
φ和
k
k
k,对于k,暂时无法直接求出,因为并没有足够的信息能够求出这个值(在下面会使用到扩展欧几里得算法进行求解),对于
φ
\varphi
φ,其中又包含了两个参数p
和q
,对于p
和q
的求解,我们可以使用枚举的思想,利用给出的公式
d
=
p
⋅
q
d = p \cdot q
d=p⋅q和p q
都是质数这两个条件进行求解。
求解参数 p p p 和参数 q q q
一个规律是:对于一个数,如果这个数是由两个质数相乘得来的,那么这个数的因子只包含1
和它本身
以及相乘而来的两个质数
。如:
35
=
5
×
7
35 = 5 \times 7
35=5×7,那么35
的因子有1 35 5 7
这四个数。
利用这个规律,我们可以设计出如下算法:
// 寻找pq的值
void Find(long long n, long long &p, long long &q){
int ans;
for(long long i = 2;i * i <= n;i ++){
if(n % i != 0){
continue;
}
p = i;
q = n / p;
}
return ;
}
如此我们便找到了两个参数p
和q
,接下来便到了真正要求解参数e
的时候了我们得到了参数
φ
\varphi
φ,因此原公式
d
⋅
e
−
k
φ
=
1
d\cdot e - k\varphi = 1
d⋅e−kφ=1,只剩下了两个参数k
,和我们需要的参数e
,这就变为了求解一个二元一次方程组,对于二元一次方程组,要想求出两个未知量,我们至少需要直到两个等式关系,但是这里我们只知道了一组等式关系,因此无法使用常规的思想进行求解。但是观察到等式右边的值为1
,如果了解扩展欧几里得算法的小伙伴就会想到,这个方程可以使用扩展欧几里得的方法进行求解。
扩展欧几里得算法
对于扩展欧几里得算法,百度上是这样解释的。
对于公式:
a
x
+
b
y
=
gcd
(
a
,
b
)
ax + by = \gcd(a, b)
ax+by=gcd(a,b),gcd(a, b)
表示a
和b
的最大公约数。一个理解方式是:如果a
,b
是整数,那么一定存在整数x
和y
,能使得公式
a
x
+
b
y
=
gcd
(
a
,
b
)
ax + by = \gcd(a, b)
ax+by=gcd(a,b)成立。换句话说:如果公式
a
x
+
b
y
=
C
ax + by = C
ax+by=C成立,那么
C
C
C一定是
gcd
(
a
,
b
)
\gcd (a,b)
gcd(a,b)的若干倍。
对于扩展欧几里得算法由如下公式:
公式推导:
a 1 ⋅ x 1 + b 1 ⋅ y 1 = gcd ( a 1 , b 1 ) a_1 \cdot x_1 + b_1 \cdot y_1 = \gcd (a_1, b_1) a1⋅x1+b1⋅y1=gcd(a1,b1)
a 2 = ( b 1 ) ⋅ x 2 + b 2 = ( a 1 % b 1 ) = ⋅ y 2 = gcd ( a 2 , b 2 ) a_2=(b1) \cdot x_2 + b_2 = (a_1 \% b_1) = \cdot y_2 = \gcd (a_2, b_2) a2=(b1)⋅x2+b2=(a1%b1)=⋅y2=gcd(a2,b2)
a 3 = ( b 2 ) ⋅ x 3 + b 3 = ( a 2 % b 2 ) ⋅ y 3 = gcd ( a 3 , b 3 ) a_3 = (b2) \cdot x_3 + b_3 = (a_2 \% b2) \cdot y_3 = \gcd (a_3, b_3) a3=(b2)⋅x3+b3=(a2%b2)⋅y3=gcd(a3,b3)
⋮ \vdots ⋮
a i − 1 = ( b i − 2 ) ⋅ x i − 1 + b i − 1 = ( a i − 2 % b i − 2 ) ⋅ y i − 1 = g c d ( a i − 1 , b i − 1 ) a_{i-1} = (b_{i - 2})\cdot x_{i - 1} + b_{i - 1} = (a_{i - 2} \% b_{i - 2}) \cdot y_{i - 1} = gcd(a_{i - 1}, b_{i - 1}) ai−1=(bi−2)⋅xi−1+bi−1=(ai−2%bi−2)⋅yi−1=gcd(ai−1,bi−1)
a i = ( b i − 1 ) ⋅ x i + b i = ( a i − 1 % b i − 1 ) ⋅ y i = g c d ( a i , b i ) a_i = (b_{i - 1})\cdot x_i + b_i = (a_{i - 1} \% b_{i - 1}) \cdot y_i = gcd(a_i, b_i) ai=(bi−1)⋅xi+bi=(ai−1%bi−1)⋅yi=gcd(ai,bi)
⋮ \vdots ⋮
a n − 1 = ( b n − 2 ) ⋅ x n − 1 + b n − 1 = ( a n − 2 % b n − 2 ) ⋅ y n − 1 = g c d ( a n − 1 , b n − 1 ) a_{n-1} = (b_{n - 2})\cdot x_{n - 1} + b_{n - 1} = (a_{n - 2} \% b_{n - 2}) \cdot y_{n - 1} = gcd(a_{n - 1}, b_{n - 1}) an−1=(bn−2)⋅xn−1+bn−1=(an−2%bn−2)⋅yn−1=gcd(an−1,bn−1)
a n = ( b n − 1 ) ⋅ x n + b n = ( a n − 1 % b n − 1 ) ⋅ y n = g c d ( a n , b n ) a_n = (b_{n - 1})\cdot x_n + b_n = (a_{n - 1} \% b_{n - 1}) \cdot y_n = gcd(a_n, b_n) an=(bn−1)⋅xn+bn=(an−1%bn−1)⋅yn=gcd(an,bn)由欧几里得算法(即:辗转相除法)可以知道: gcd ( a i − 1 , b i − 1 ) = gcd ( a i , b i ) \gcd (a_{i - 1}, b_{i - 1}) = \gcd (a_i, b_i) gcd(ai−1,bi−1)=gcd(ai,bi),即无论
a
和b
的值是什么,其最大公因数永远是相等的。因此可以得到: a i = ( b i − 1 ) ⋅ x i − 1 + b i = ( a i − 1 % b i − 1 ) ⋅ y i − 1 = a i − 1 = ( b i − 2 ) ⋅ x i + b i − 1 = ( a i − 2 % b i − 2 ) ⋅ y i a_i = (b_{i - 1})\cdot x_{i - 1} + b_i = (a_{i - 1} \% b_{i - 1}) \cdot y_{i - 1} = a_{i-1} = (b_{i - 2})\cdot x_i + b_{i - 1} = (a_{i - 2} \% b_{i - 2}) \cdot y_i ai=(bi−1)⋅xi−1+bi=(ai−1%bi−1)⋅yi−1=ai−1=(bi−2)⋅xi+bi−1=(ai−2%bi−2)⋅yi
因为: a % b = a − a b × b a \% b = a - \frac{a}{b} \times b a%b=a−ba×b,带入到上述公式中得可以得到: a i − 1 ⋅ x i − 1 + b i − 1 ⋅ y i − 1 = b i − 1 ⋅ x i + ( a i − 1 − ( a i − 1 / b i − 1 ) × b i − 1 ) ⋅ y i a_{i - 1} \cdot x_{i - 1} + b_{i - 1} \cdot y_{i - 1} = b_{i - 1} \cdot x_i + (a_{i - 1} - (a_{i - 1} / b_{i - 1}) \times b_{i - 1}) \cdot y_i ai−1⋅xi−1+bi−1⋅yi−1=bi−1⋅xi+(ai−1−(ai−1/bi−1)×bi−1)⋅yi,整理可得: a i − 1 ⋅ x i − 1 + b i − 1 ⋅ y i − 1 = a i − 1 ⋅ y i + b i − 1 ⋅ ( x i − a i − 1 b i − 1 ⋅ y i ) a_{i - 1} \cdot x_{i - 1} + b_{i - 1} \cdot y_{i - 1} = a_{i - 1} \cdot y_i + b_{i - 1} \cdot (x_i - \frac{a_{i - 1}}{b_{i - 1}}\cdot y_i) ai−1⋅xi−1+bi−1⋅yi−1=ai−1⋅yi+bi−1⋅(xi−bi−1ai−1⋅yi)
可以发现如下规律:
x i − 1 = y i x_{i - 1} = y_i xi−1=yi
y i − 1 = x i − a i − 1 b i − 1 ⋅ y i y_{i - 1} = x_i - \frac{a_{i - 1}}{b_{i - 1}}\cdot y_i yi−1=xi−bi−1ai−1⋅yi
并且由欧几里得算法可以得到:最后 b n = 0 b_n = 0 bn=0, a n = g c d ( a , b ) a_n = gcd(a, b) an=gcd(a,b)
如果我们知道了
gcd(a, b)
,那么我们可任意设定 y n y_n yn的值,因为 y n y_n yn的参数 b n = 0 b_n = 0 bn=0,并且设定 x n x_n xn的值为 g c d ( a , b ) gcd(a, b) gcd(a,b),再利用上面得到的规律,可以递归的求解出 x 1 x_1 x1和 y 1 y_1 y1的值。举例:对于 a n = ( b n − 1 ) ⋅ x n + b n = ( a n − 1 % b n − 1 ) ⋅ y n = g c d ( a n , b n ) a_n = (b_{n - 1})\cdot x_n + b_n = (a_{n - 1} \% b_{n - 1}) \cdot y_n = gcd(a_n, b_n) an=(bn−1)⋅xn+bn=(an−1%bn−1)⋅yn=gcd(an,bn),我们可以求解出 x n x_n xn和 y n y_n yn(因为这两个值是设定出来的),然后 x n − 1 = y n y n − 1 = x n − a n − 1 b n − 1 ⋅ y n x_{n - 1} = y_n~~~y_{n - 1} = x_n - \frac{a_{n - 1}}{b_{n - 1}}\cdot y_n xn−1=yn yn−1=xn−bn−1an−1⋅yn,如此便可递归的求解出 x 1 x_1 x1和 y 1 y_1 y1了。
因为公式 d ⋅ e − k φ = 1 d\cdot e - k\varphi = 1 d⋅e−kφ=1中 d d d与 φ \varphi φ是互质的,也就是 gcd ( d , φ ) = 1 \gcd(d, \varphi) = 1 gcd(d,φ)=1,正好可以使用扩展欧几里得算法进行求解这个二元一次方程组,相当于已经知道了 gcd ( d , φ ) \gcd(d, \varphi) gcd(d,φ)的值, d ⋅ e − k φ = gcd ( d , φ ) = 1 d\cdot e - k\varphi = \gcd(d, \varphi) = 1 d⋅e−kφ=gcd(d,φ)=1。
代码实现:
long long ex_gcd(long long a, long long b, long long &x, long long &y){ // 这里的参数x,y一定要用引用的方式传参
if(!b){ // 如果b == 0, 表明已经递归到最后一个了,就设定y = 0, x = 1(表示a和b的最大公因子)
x = 1;
y = 0;
return a; // 到达最后一个公式后就进行返回a,a表示的是第一个式子的最大公因子
}
long long d = e_gcd(b, a % b, x, y); // 记录下一个式子的返回的a的值,因为是递归的关系,最终记录的是最后一个式子的a的值。
long long t = x; // 使用临时变量记录一下下一个式子得到的x的值
x = y; // 更新当前式子的x的值
y = t - a / b * y; // 更新当前式子的y的值
return d; // 最后返回d,d的值是由最后一个公式的a的值进行传递过来的,即(a, b)的最大公因子
}
如此我们便可以求得e
,k
,的值了,如果上述代码返回的不是1
,即(a, b)
的最大公因子不是1
,说明没有解,即:a
与b
的最大公因子不是1
,那么就直接输出-1
,如果返回的是1
,表明有解,并且已经求出解了,即:e = x, k = y
。为了防止e为负数,需要对计算出的结果做如下运算:
e
=
(
e
m
o
d
φ
+
φ
)
m
o
d
φ
e = (e \mod \varphi + \varphi) \mod \varphi
e=(emodφ+φ)modφ。
如何理解公式 e = ( e m o d φ + φ ) m o d φ e = (e \mod \varphi + \varphi) \mod \varphi e=(emodφ+φ)modφ呢?
通俗的解释:
因为
e
满足公式 e ⋅ d ≡ 1 m o d φ ( n ) e\cdot d \equiv 1 \mod \varphi(n) e⋅d≡1modφ(n) ,也就是 e ⋅ d e\cdot d e⋅d与1
在模 φ \varphi φ下余数相等,因此为了确保e
为正值,我们可以利用公式 e = ( e m o d φ + φ ) m o d φ e = (e \mod \varphi + \varphi) \mod \varphi e=(emodφ+φ)modφ来使e
保持 0 − φ 0 - \varphi 0−φ的范围内,举个例子:如果a = -3
,b = 17
,m = 5
,那么 − 3 ≡ 17 ( m o d 5 ) -3 \equiv 17 \pmod{5} −3≡17(mod5),因为-3
除以5
的余数为2
,17
除以5
的余数也为2
,为了保证a
为正值,我们可以令: ( − 3 m o d 5 + 5 ) m o d 5 = ( 2 + 5 ) m o d 5 = 2 (-3 \mod 5 + 5) \mod 5 = (2 + 5) mod 5 = 2 (−3mod5+5)mod5=(2+5)mod5=2。得到 a = 2 a = 2 a=2,并且a
与5
进行取余得到的结果也为2
。较为官方的解释:
保持同余性质:在RSA算法中,
e
和d
必须满足 e ⋅ d ≡ 1 m o d φ ( n ) e\cdot d \equiv 1 \mod \varphi(n) e⋅d≡1modφ(n) 表示 e ⋅ d e\cdot d e⋅d与1
在模 φ \varphi φ下余数相等,这是加密和解密正确性的基础。如果e
为负数,直接取模可能会导致e
和d
不满足同余性质。通过使用 e = ( e m o d φ + φ ) m o d φ e = (e \mod \varphi + \varphi) \mod \varphi e=(emodφ+φ)modφ 这样的方法,可以保持e
在模 φ \varphi φ 下的同余性质不变,同时确保e
为正值。在数论中,同余性质是指两个整数除以同一个正整数所得的余数相同。形式上,如果两个整数
a
和b
除以正整数m
所得的余数相同,则称a
和b
在模m
下同余,记作 a ≡ b ( m o d m ) a \equiv b \pmod{m} a≡b(modm)。例如,如果a = 7
,b = 17
,m = 5
,那么 7 ≡ 17 ( m o d 5 ) 7 \equiv 17 \pmod{5} 7≡17(mod5),因为7
除以5
的余数为2
,17
除以5
的余数也为2
。
在求解出e
之后,我们可以直接使用公式:
X
=
C
e
m
o
d
n
X = C^e \mod n
X=Cemodn,将值进行带入即可,但是又因为
C
C
C的值非常大,我们需要用到快速幂的方法,又因为快速幂中存在乘法运算,极易导致内存溢出的现象(在很大的数的情况下),因此我们需要在快速幂的基础上使用快速乘的方法进行运算(在计算机中,计算加法的速度往往比计算乘法的速度要快),并且数值都要使用long long的类型。
代码:
// RSA解密
#include<iostream>
#include<math.h>
#include<vector>
using namespace std;
typedef long long ll;
// 最大公约数
int gcd(int a, int b){
return b == 0? a : gcd(b, a % b);
}
// 扩展欧几里得算法
long long e_gcd(long long a, long long b, long long &x, long long &y){
if(!b){ // 如果b == 0
x = 1;
y = 0;
return a;
}
long long d = e_gcd(b, a % b, x, y);
long long t = x;
x = y;
y = t - a / b * y;
return d;
}
// 快速乘算法
ll FastTimes(ll num, ll times, ll n){
ll ans = 0; // 这里要初始化为0
num %= n;
while(times){
if(times & 1){
ans += num;
ans %= n;
times --;
}else{
times >>= 1;
num += num;
num %= n;
}
}
return ans;
}
// 快速幂算法
ll FastPower(ll base, ll index, ll n){
ll ans = 1;
base %= n;
while(index){
if(index & 1){
ans = FastTimes(ans, base, n);
index--;
}else{
index >>= 1;
base = FastTimes(base, base, n);
}
}
return ans;
}
// 寻找pq的值
void FindPQ(ll n, ll &p, ll &q){
int ans;
for(ll i = 2;i * i <= n;i ++){
if(n % i != 0){
continue;
}
p = i;
q = n / p;
}
return ;
}
int solve(){
ll n = 1001733993063167141;
ll c = 20190324;
ll d = 212353;
ll p = -1, q = -1;
// FindPQ(n, p, q); // 找到p q的值
p=891234941,q=1123984201;
// 找到p 和 q之后继续寻找e
ll fy = (p - 1) * (q - 1);
ll _x, _y;
ll gc = e_gcd(d, fy, _x, _y);
ll e;
if(gc == 1){
e = (_x%fy + fy)%fy;
}else{
return -1;
}
ll X = FastPower(c, e, n);
cout<<X<<endl;
return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
ll t = 1;
while(t--){
solve();
}
return 0;
}