蓝桥杯 — — RSA解密

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=pq d m o d    ( p − 1 ) ⋅ ( q − 1 ) = 1 d \mod {(p - 1) \cdot (q - 1)} = 1 dmod(p1)(q1)=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 (de)mod((p1)(q1))=1。使用更易懂的公式可表述为: d ⋅ e − k ( ( p − 1 ) ⋅ ( q − 1 ) ) = 1 ,(其中 k 是一个未知量) d\cdot e - k((p - 1)\cdot (q - 1)) = 1,(其中k是一个未知量) dek((p1)(q1))=1,(其中k是一个未知量),意思是:对于 d ⋅ e d \cdot e de,可以减去 k k k ( p − 1 ) ⋅ ( q − 1 ) (p - 1)\cdot (q - 1) (p1)(q1),使得最后的差值为 1 1 1

对公式 d ⋅ e − k ( ( p − 1 ) ⋅ ( q − 1 ) ) = 1 ,(其中 k 是一个未知量) d\cdot e - k((p - 1)\cdot (q - 1)) = 1,(其中k是一个未知量) dek((p1)(q1))=1,(其中k是一个未知量) 的理解:

举个例子:假设 d ⋅ e = 16 d \cdot e = 16 de=16 ( p − 1 ) ⋅ ( q − 1 ) = 5 (p - 1)\cdot (q - 1) = 5 (p1)(q1)=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 (de)mod((p1)(q1))=1   16mod5=1,这个意思是使16除以5的余数为1,因为除法和减法有着非常大的联系(除以一个数的值等于减去这个数的次数,余数等于相减之后的差值),因此我们可以从新将其写为 16 − k ⋅ 5 = 1 16 - k\cdot 5 = 1 16k5=1,即16 减去多少个5后值为1

为了方便书写,我们设 φ = ( p − 1 ) ⋅ ( q − 1 ) \varphi = (p - 1)\cdot(q - 1) φ=(p1)(q1),这样公式就又化简为了 d ⋅ e − k φ = 1 ,(其中 k 是一个未知量) d\cdot e - k\varphi = 1,(其中k是一个未知量) dekφ=1,(其中k是一个未知量),由于又涉及到了两个新的未知量 φ \varphi φ k k k,要想求出 e e e,我们需要提前求出 φ \varphi φ k k k,对于k,暂时无法直接求出,因为并没有足够的信息能够求出这个值(在下面会使用到扩展欧几里得算法进行求解),对于 φ \varphi φ,其中又包含了两个参数pq,对于pq的求解,我们可以使用枚举的思想,利用给出的公式 d = p ⋅ q d = p \cdot q d=pqp 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 ;
} 

如此我们便找到了两个参数pq,接下来便到了真正要求解参数e的时候了我们得到了参数 φ \varphi φ,因此原公式 d ⋅ e − k φ = 1 d\cdot e - k\varphi = 1 dekφ=1,只剩下了两个参数k,和我们需要的参数e,这就变为了求解一个二元一次方程组,对于二元一次方程组,要想求出两个未知量,我们至少需要直到两个等式关系,但是这里我们只知道了一组等式关系,因此无法使用常规的思想进行求解。但是观察到等式右边的值为1,如果了解扩展欧几里得算法的小伙伴就会想到,这个方程可以使用扩展欧几里得的方法进行求解。

扩展欧几里得算法

对于扩展欧几里得算法,百度上是这样解释的。

请添加图片描述

对于公式: a x + b y = gcd ⁡ ( a , b ) ax + by = \gcd(a, b) ax+by=gcd(a,b)gcd(a, b)表示ab的最大公约数。一个理解方式是:如果ab是整数,那么一定存在整数xy,能使得公式 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) a1x1+b1y1=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}) ai1=(bi2)xi1+bi1=(ai2%bi2)yi1=gcd(ai1,bi1)
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=(bi1)xi+bi=(ai1%bi1)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}) an1=(bn2)xn1+bn1=(an2%bn2)yn1=gcd(an1,bn1)
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=(bn1)xn+bn=(an1%bn1)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(ai1,bi1)=gcd(ai,bi),即无论ab的值是什么,其最大公因数永远是相等的。

因此可以得到: 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=(bi1)xi1+bi=(ai1%bi1)yi1=ai1=(bi2)xi+bi1=(ai2%bi2)yi

因为: a % b = a − a b × b a \% b = a - \frac{a}{b} \times b a%b=aba×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 ai1xi1+bi1yi1=bi1xi+(ai1(ai1/bi1)×bi1)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) ai1xi1+bi1yi1=ai1yi+bi1(xibi1ai1yi)

可以发现如下规律:

x i − 1 = y i x_{i - 1} = y_i xi1=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 yi1=xibi1ai1yi

并且由欧几里得算法可以得到:最后 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=(bn1)xn+bn=(an1%bn1)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 xn1=yn   yn1=xnbn1an1yn,如此便可递归的求解出 x 1 x_1 x1 y 1 y_1 y1了。

因为公式 d ⋅ e − k φ = 1 d\cdot e - k\varphi = 1 dekφ=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 dekφ=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)的最大公因子
}

如此我们便可以求得ek,的值了,如果上述代码返回的不是1,即(a, b)的最大公因子不是1,说明没有解,即:ab的最大公因子不是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) ed1modφ(n) ,也就是 e ⋅ d e\cdot d ed1在模 φ \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 = -3b = 17m = 5,那么 − 3 ≡ 17 ( m o d 5 ) -3 \equiv 17 \pmod{5} 317(mod5),因为 -3 除以 5 的余数为 217 除以 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,并且a5进行取余得到的结果也为2

较为官方的解释:

保持同余性质:在RSA算法中,ed 必须满足 e ⋅ d ≡ 1 m o d    φ ( n ) e\cdot d \equiv 1 \mod \varphi(n) ed1modφ(n) 表示 e ⋅ d e\cdot d ed1在模 φ \varphi φ下余数相等,这是加密和解密正确性的基础。如果 e 为负数,直接取模可能会导致 ed 不满足同余性质。通过使用 e = ( e m o d    φ + φ ) m o d    φ e = (e \mod \varphi + \varphi) \mod \varphi e=(emodφ+φ)modφ 这样的方法,可以保持 e 在模 φ \varphi φ 下的同余性质不变,同时确保 e为正值。

在数论中,同余性质是指两个整数除以同一个正整数所得的余数相同。形式上,如果两个整数 ab 除以正整数 m 所得的余数相同,则称 ab 在模 m下同余,记作 a ≡ b ( m o d m ) a \equiv b \pmod{m} ab(modm)。例如,如果 a = 7b = 17m = 5,那么 7 ≡ 17 ( m o d 5 ) 7 \equiv 17 \pmod{5} 717(mod5),因为 7 除以 5 的余数为 217 除以 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;
} 

在这里插入图片描述

  • 37
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值