RSA密码初探
程序员文章站
2024-03-19 12:17:40
...
RSA密码初探
一。 RSA公私钥生成
1.随机选定两个大素数p, q.
2.计算公钥和私钥的公共模数 n = pq .
3.计算模数n的欧拉函数 φ(n) .
4.选定一个正整数e,使1 < e < φ(n) ,且e与φ(n)互质.(e取最小)
5.计算d,满足 de ≡ 1 (mod φ(n) )(d取最小)
6.n与e决定公钥, n与d决定私钥.
二。加解密
该过程为L给Z发消息,公钥为Z的公钥(n & e), 私钥为Z的私钥(n & d).
1.L欲给Z发一个消息M,他先把M转换为一个大数m < n, 然后用Z的公钥(n & e)把m加密为另一个大数: c = m^e mod n
2.Z收到L发来的大数c,着手解密.通过自己的私钥(n & d),得到原来的大数m:
m = c^d mod n
3.再把m转换为M, Z即得到L的原始消息.
这个过程之所以能通过,是因为有如下等式:
c^d ≡(m^e)^d ≡ m ^(ed) (mod n)
若给出p,q,和密文整数序列a[m] ,求解公钥n,e,私钥n,d以及解出明文序列b[m]
1)令x = φ(n) = φ(p) * φ(q) = (p-1)(q-1) (p,q互质且p,q都是质数)
2)e是与x互质的最小正整数,枚举即可
3)de ≡ 1 (mod φ(n) ) ,d最小,枚举,或者逆元(扩欧几里得求逆元,非快速幂)。
4)b[i] = ( a[i] ^ d ) % n (也就是过程2)(快速幂取模即可)(有时候可能爆精度快速幂中嵌套快速乘)
例题:
密码破译
描述
近日来勒索病毒的事件频繁发生,小Y对它的加密原理非常感兴趣,研究了一番相关知识之后,他就来给你看他的加密程序,并给你一段密文,和你炫耀说就算把程序给你看你也**不出来。
你扫了一眼代码发现加密的公式为b =a ^ e%m,其中e是质数。
进一步分析发现m=p∗q,p和q都为质数,p!=q,
作为一个计算机高手,你早就对加密算法烂熟于心,一眼就看出这个程序的算法和原理,找到了**的方法,发现小Y疏忽在与给了你一个不够大的m。
你知道解密的公式与加密对称,为a=bd%m。
但是你仍然无法心算解出这个d,因此你需要借助计算机来将密文**。
输入
第一行有一个整数T表示数据组数。(T<=100)
接着有T组数据,每组数据两行。
第一行有四个数e、p、q和n,其中e、p、q如题所描述,n表示需要解密的数字序列长度。
第二行是需要解密的数字序列a1…an。
1<p,q,e<=108,p、q、e为质数且p!=q。
0<= ai 保证解密的结果即原数列的值小于min(p,q)并大于等于0
1<=n<=100
保证m有且仅有两个不同的质因数p和q,并且一定存在一个题中描述的参数d使得解密公式能够无损解密出所有0~min(p,q)−1范围之间的数字。
输出
对于每组数据输出一行,表示解密后的数字序列,数字之间以空格隔开。
样例输入1
1
5 19 29 3
335 440 514
样例输出1
65 67 77
提示
对于样例,存在d=101使得解密公式成立。
注意m和ai的大小可能超过int的范围
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
typedef long long ll;
ll exgcd(ll a, ll b,ll &x,ll &y){
if(!b){
return x = 1, y = 0, a;
}
ll d = exgcd(b , a % b, x, y);
ll t = x;
x = y, y = t - (a / b) * y;
return d;
}
ll get_inv(ll a,ll mod){
ll x,y;
exgcd(a,mod,x,y);
return (x % mod + mod)%mod;
}
ll mul(ll a,ll b,ll mod){
ll res = 0;
while(b){
if(b&1) res = (res + a) % mod;
a = a * 2 % mod;
b >>= 1;
}
return res;
}
ll fast_pow(ll a,ll b,ll mod){
ll res = 1;
while(b){
if(b&1) res = mul(res,a,mod);
a = mul(a,a,mod);
b >>= 1;
}
return res;
}
ll a[maxn];
int main(){
ll p,q,e;
int T,n;
scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld%d",&e,&p,&q,&n);
for(int i = 0; i < n; ++i){
scanf("%lld",&a[i]);
}
ll m = p * q;
ll d = get_inv(e,(p - 1) * (q - 1));
for(int i = 0; i < n; ++i){
printf("%lld",fast_pow(a[i],d,m));
putchar((i == n - 1)?'\n':' ');
}
}
return 0;
}