RSA算法是优秀的公钥密码算法,使用十分广泛。
RSA可用于加密、签名等,应用于PKI。
1)初始化:随机选择两个大素数p、q, n = p * q
2) 密钥生成:随机选择整数e , 1<e<(p-1)(q-1),且 gcd(e,(p-1)(q-1))=1,求e*d=1 mod (p-1)(q-1)
3)公钥(e,n),私钥 ( d )
加密 明文 m<n ,密文 c=m^e mod n
解密 明文 m = c^d mod n
小素数情况下的实现:
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
- typedef long long ULL;
- ULL extended_eculid(ULL a , ULL b, ULL &s, ULL &t)//扩展Eculid定理
- {
- if(b == 0)
- {
- s = 1;
- t = 0;
- return a;
- }
- ULL d, x, y;
- d = extended_eculid(b,a % b,x,y);
- s = y;
- t = x - a/b*y;
- return d;
- }
- ULL Squ_Mul(ULL a, ULL b, ULL n)//模重复平方法求(a^b)mod n
- {
- ULL ans;
- ans = 1;
- while(b!=0)
- {
- if(b&1==1)
- ans = (ans*a)%n;
- a = (a*a)%n;
- b>>=1;
- }
- return ans;
- }
- int Miller_Rabin(ULL n,int k)//Miller_Rabin素性测试
- {
- ULL m = n - 1;
- int i;
- while((m%2)!=1)
- m>>=1;
- ULL a;
- while(1)
- {
- time_t random = time(NULL);
- a = random%(n-1);
- if(a!=0 && a!=1)
- break;
- }
- ULL b = Squ_Mul(a,m,n);
- if(b == 1)
- return 1;
- for(i = 0; i < k; i++)
- {
- if( b == n -1)
- {
- return 1;
- }
- else
- {
- b = ((b%n)*(b%n))%n;
- }
- }
- return 0;
- }
- int menu()//菜单
- {
- int select=1;
- printf("***********RSA**********\n");
- printf("1 生成素数对和密钥对\n");
- printf("2 加密\n");
- printf("3 解密\n");
- printf("0 退出\n");
- printf("***********************\n");
- while(1)
- {
- printf("请选择:");
- scanf("%d",&select);
- if(select == 0 || select == 1 || select == 2 || select == 3)
- return select;
- }
- }
- ULL GenPrime( ULL &p, int bitNum,int k)//生成素数
- {
- // p = 1;
- // p |= (1<<(bitNum -1));
- time_t random = time(NULL);
- int count = 100;
- ULL con = 1<<bitNum;
- if(p%2==0)
- p = (p+1)%con;
- while(count)
- {
- if(Miller_Rabin(p,k))
- return 1;
- p = (p+time(NULL))%con;
- p |= (1<<(bitNum -1));
- if(p%2==0)
- p = (p+1)%con;
- // p = (p+2)%con;
- if(p == 0 || p == 1)
- p = 3;
- count--;
- }
- return 0;
- }
- void GenPQ(ULL &p, ULL &q)
- {
- int BitNumP = 10,BitNumQ = 10;
- printf("请输入要生成的素数 P 的bit位数(4<=bit<31):");
- scanf("%d",&BitNumP);
- p = q = 3;
- p|=1<<(BitNumP-1);
- if(GenPrime(p,BitNumP,5) == 0)
- {
- printf("没有找到素数p\n");
- exit(0);
- }
- printf("请输入要生成的素数 Q 的bit位数(4<=bit<31):");
- scanf("%d",&BitNumQ);
- q|=1<<(BitNumQ-1);
- int count = 100;
- while(count)
- {
- if(GenPrime(q,BitNumQ,5)==0)
- {
- printf("没有找到素数q\n");
- exit(0);
- }
- if(q!=p)
- break;
- else
- q = q + 2;
- count--;
- }
- if(count == 0)
- {
- printf("没有找到素数q\n");
- exit(0);
- }
- }
- int main()
- {
- int select = menu();
- ULL m,n,c;
- ULL Euler_N;
- ULL e,d=0;
- while(select)
- {
- switch (select)
- {
- case 1:
- {
- ULL p,q;
- p = q = 0;
- GenPQ(p,q);//生成P Q
- n = p*q;
- Euler_N = (p-1)*(q-1);//计算欧拉函数值
- time_t random = time(NULL);
- int count = 100;
- ULL t = 0;
- for(e = 3; e < Euler_N; e+=2)
- {
- if(extended_eculid(e,Euler_N,d,t) == 1)
- break;
- }
- d = (d+Euler_N)%Euler_N;
- if(e>=Euler_N)
- {
- printf("没有合适的e\n");
- exit(0);
- }
- printf(" p= %lld q= %lld n= %lld e= %lld d= %lld \n",p,q,n,e,d);
- /* while(count)
- {
- e = time(0);
- e|= 1;
- e = e%Euler_N;
- if(e!=0 && e!=1 && extended_eculid(e,Euler_N,d,t) == 1)
- {
- break;
- }
- count--;
- }
- if(count==0)
- {
- printf("没有e\n");
- exit(0);
- }*/
- break;
- }
- case 2: //用公钥加密
- {
- printf("导入公钥 N :");
- scanf("%lld",&n);
- printf(" n= %lld ",n);
- printf("导入公钥 E :");
- scanf("%lld",&e);
- printf(" e= %lld \n",e);
- ULL leftLen = n/(1<<30);//此处主要是控制m不能太小,否则得到的C太大,计算时会溢出,出错
- ULL rightLen = (n<(1<<30))?n:(1<<30);//m也不能太大,否则计算m^e mod n时,m*m会有问题
- printf("请输入明文(%lld<m<%lld) :",leftLen,rightLen);
- scanf("%lld",&m);
- if(m>=rightLen || m<=leftLen)
- {
- printf("明文分组不符合要求!\n");
- break;
- }
- printf(" m=%lld ",m);
- c = Squ_Mul(m,e,n);
- printf(" c= %lld \n",c);
- break;
- }
- case 3: //用私钥解密
- {
- printf("导入公钥 N :");
- scanf("%lld",&n);
- printf(" n= %lld ",n);
- printf("导入私钥 D :");
- scanf("%lld",&d);
- printf(" d= %lld \n",d);
- printf("请输入密文 :");
- scanf("%lld",&c);
- printf(" c=%lld ",c);
- m = Squ_Mul(c,d,n);
- printf(" m= %lld \n",m);
- break;
- }
- default:break;
- }
- select = menu();
- }
- return 0;
- }
转载于:https://blog.51cto.com/andydhu/835211