公钥算法之RSA算法

与背包算法一样,这算法也是一个非对称算法。这里不写证明之类的定理推论了,需要的话网上可以搜到到很多,书本例如算法导论也有详细的证明。简写一下算法的步骤:

(1)选择两个大素数 PQ ,其中P!=Q(这里使用 Miller_Rabin近似算法 确定素数)
(2)计算 N=P*Q
(3)选择一个小奇数作为公钥(加密密钥) E,使其与 (P-1)* (Q-1)互质(使用 扩展欧几里德算法 求出)
(4)选择私钥(解密密钥) D,满足如下条件:
          (D*E) mod (P-1)(Q-1)=1(使用 扩展欧几里德Extend_Euclid(E,(P-1)*(Q-1))=1,求E的逆元,即为D)
(5)加密时,明文 PT计算密文 CT如下:
          CT=PT^ E  mod N (使用 反复平方求数的幂 来加密和解密)
(6)解密时,从密文 CT计算明文 PT如下:
          PT=CT^ D  mod N
 
代码如下,有错还请指出:
#include <stdio.h>

#include <stdlib.h>

#include <time.h>

int bi[1000];



typedef struct Tri//三元组结构

{

	__int64 d,x,y;

}Tri;



__int64 Modular_Exponentiation(__int64 a,__int64 b,__int64 n)

{

	__int64 i,c=0,d=1;

	for(i=0;b;i++)//十进制转为二进制

	{

		bi[i]=b%2;

		b=b>>1;

	}

	for(i=i-1;i>=0;i--)//由二进制高位开始反复平方

	{//变量c没实际用处,只用来理解运算过程

		c=c*2,d=d*d%n;

		if(bi[i]) c=c+1,d=d*a%n;

//		printf("%I64d: bi=%I64d c=%I64d d=%I64d\n",i,bi[i],c,d);

	}

	return d;

}



bool Witness(__int64 a,__int64 n)

{//以a作基,测试n是否为合数,返回true为合数,false不为合数。

	__int64 x,temp,i,b=n-1,t,len,u=0,sum;//n-1=2^t*u,u为奇数

	for(i=0;b;i++) {bi[i]=b%2;b=b>>1;}

	len=i-1;

	for(i=t=0;!bi[i];i++) t++;

	for(i=t;i<=len;i++)//求出u

	{

		temp=i-t;

		if(bi[i]==0) continue;

		sum=1;

		while(temp)

		{

			sum*=2;

			temp--;

		}

		u+=sum;

	}

//	printf("u=%I64d\n",u);

	x=Modular_Exponentiation(a,u,n);

	for(i=0;i<t;i++)

	{

		temp=x;

		x=x*x%n;

		if(x==1&&temp!=1&&temp!=n-1)

			return true;//仅当n为合数时,对模n才可能存在1的非平凡平方根

	}

	if(x!=1) return true;//费马定理

	return false;

}



bool Miller_Rabin(__int64 n,__int64 s)

{//判断素数

	__int64 i,a;

	for(i=0;i<s;i++)

	{

		a=0;

		while(!a) a=rand()%n+1;

//		printf("a=%I64d\n",a);

		if(Witness(a,n)) return false;//确定是合数

	}

	return true;//很可能是素数

}



Tri Extend_Euclid(__int64 a,__int64 b)

{//扩展欧几里德算法

	Tri t,t2;

	if(b==0) {t.d=a,t.x=1,t.y=0;return t;}

	t2=Extend_Euclid(b,a%b);

	t.d=t2.d;t.x=t2.y;t.y=t2.x-a/b*t2.y;

	return t;

}



__int64 Find_E(__int64 n)

{//寻找与(P-1)*(Q-1)互质的小奇数E

	Tri t;

	__int64 i;

	do

	{

		i=rand()%97+3;//随即生成3-100内的数

//		printf("i=%I64d\n",i);

		if(i%2)//判断是否奇数

			t=Extend_Euclid(i,n);

		if(t.d==1) return i;//若互质,找到

	}while(1);

	return 0;

}



__int64 Encode(__int64 PT,__int64 E,__int64 N)

{

	__int64 CT;

	CT=Modular_Exponentiation(PT,E,N);

	return CT;

}



__int64 Decode(__int64 CT,__int64 D,__int64 N)

{

	__int64 PT;

	PT=Modular_Exponentiation(CT,D,N);

	return PT;

}



void RSA()

{

	Tri t;

	__int64 D,E,N,P,Q,sign,input,CT,PT;

	srand(time(NULL));



	do//假设随机选出50-100内的素数P

	{

		P=rand()%50+50;

//		printf("P:%I64d\n",P);

	}while(!Miller_Rabin(P,10));



	do//假设随机选出50-100内的素数Q

	{		

		Q=rand()%50+50;

		if(P==Q) continue;//P不能等于Q

//		printf("Q:%I64d\n",Q);

	}while(!Miller_Rabin(Q,10));



	printf("随机素数P=%I64d,Q=%I64d\n",P,Q);

	N=P*Q;

	printf("N=P*Q=%I64d\n",N);



	E=Find_E((P-1)*(Q-1));//随即产生公钥

	printf("公钥E为:%I64d\n",E);



	t=Extend_Euclid(E,(P-1)*(Q-1));//求逆元私钥

	D=t.x;

	while(D<=0) D+=(P-1)*(Q-1);//将负逆元转正



	printf("私钥D为:%I64d\n",D);

	printf("请输入解密(0)/加密(1)标记和数字文本(%I64d<=数字<=%I64d)\n",-N+2,N-2);

	printf("输入:%I64d %I64d退出\n",N,N);

	while(scanf("%I64d %I64d",&sign,&input),sign!=N||input!=N)

	{

		if(sign)//加密

		{

			CT=Encode(input,E,N);

			printf("加密后密文:%I64d\n",CT);

		}

		else//解密

		{

			PT=Decode(input,D,N);

			printf("解密后明文:%I64d\n",PT);

		}

	}

	return ;

}



int main()

{

	RSA();

	return 0;

}

在这里感谢高老师的辛勤教导!

你可能感兴趣的:(rsa)