公钥算法之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;
}
在这里感谢高老师的辛勤教导!
posted @ 2011-08-11 19:13  Veegin  阅读(2517)  评论(0编辑  收藏  举报