RSA加解密算法

来源:互联网 发布:网络消费的社会 编辑:程序博客网 时间:2024/05/17 05:09

RSA加解密算法

算法简介

假设资料要由A机器传至B机器,那,由B机器用乱数决定一个key,我们称之为privatekey,这个key自始至终都只留在B机器里不送出来然后,由这个privatekey计算出另一个key,我们称之为publickey.这个publickey的特性是几乎不可能反演算出privatekey来然后将这个publickey透过网路丢给A机器.A机器将资料用这个publickey编码,这个编码过的资料一定得使用privatekey才解得开然后A机器将编码过的资料透过网路传给B,B再用privatekey将资料解码这时,如果有第三者窃听资料时,他只得到B传给A的publickey,以及A用这个publickey编码后的资料没有privatekey,第三者根本无法解码所以这个方法确实能防止第三者的窃听

  它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, Adi Shamir 和Leonard Adleman。但RSA的安全性一直未能得到理论上的证明。它经历了各种攻击,至今未被完全攻破。

  RSA的安全性依赖于大数分解。公钥和私钥都是两个大素数( 大于 100 个十进制位)的函数。据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积。

  密钥对的产生。选择两个大素数,p 和q 。计算:

  n = p * q

然后随机选择加密密钥e,要求 e 和 ( p - 1 ) * ( q - 1 ) 互质。最后,利用 Euclid 算法计算解密密钥d,满足

  e * d = 1 (mod ( p - 1 ) * ( q - 1 ) )

  其中n和d也要互质。数e和 n是公钥,d是私钥。两个素数p和q不再需要,应该丢弃,不要让任何人知道。

  加密信息 m(二进制表示)时,首先把m分成等长数据块 m1 ,m2,..., mi ,块长s ,其中 <= n, s 尽可能的
大。对应的密文是:

  ci = mi^e (mod n ) ( a )

解密时作如下计算:

  mi =ci^d (mod n ) ( b )

RSA 可用于数字签名,方案是用 (a ) 式签名, ( b )式验证。具体操作时考虑到安全性和 m信息量较大等因素,一般是先作 HASH 运算。

RSA 的安全性。 RSA的安全性依赖于大数分解,但是否等同于大数分解一直未能得到理论上的证明,因为没有证明破解 RSA就一定需要作大数分解。假设存在一种无须分解大数的算法,那它肯定可以修改成为大数分解算法。目前, RSA 的一些变种算法已被证明等价于大数分解。不管怎样,分解n是最显然的攻击方法。现在,人们已能分解多个十进制位的大素数。因此,模数n 必须选大一些,因具体适用情况而定。

RSA的速度。 由于进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,无论是软件还是硬件实现。速度一直是RSA的缺陷。一般来说只用于少量数据加密。

RSA的选择密文攻击。 RSA在选择密文攻击面前很脆弱。一般攻击者是将某一信息作一下伪装( Blind),让拥
    有私钥的实体签署。然后,经过计算就可得到它所想要的信息。实际上,攻击利用的都是同一个弱点,即存在这样一个事实:乘幂保留了输入的乘法结构:

( XM )^d = X^d *M^d mod n

前面已经提到,这个固有的问题来自于公钥密码系统的最有用的特征--每个人都能使用公钥。但从算法上无法解决这一问题,主要措施有两条:一条是采用好的公钥协议,保证工作过程中实体不对其他实体任意产生的信息解密,不对自己一无所知的信息签名;另一条是决不对陌生人送来的随机文档签名,签名时首先使用One-Way HashFunction 对文档作HASH处理,或同时使用不同的签名算法。在中提到了几种不同类型的攻击方法。  

RSA的公共模数攻击。 若系统中共有一个模数,只是不同的人拥有不同的e和d,系统将是危险的。最普遍的情况是同一信息用不同的公钥加密,这些公钥共模而且互质,那末该信息无需私钥就可得到恢复。设P为信息明文,两个加密密钥为e1和e2,公共模数是n,则:

C1 = P^e1 mod n

C2 = P^e2 mod n

密码分析者知道n、e1、e2、C1和C2,就能得到P。 因为e1和e2互质,故用Euclidean算法能找到r和s,满足:

r * e1 + s * e2 = 1

假设r为负数,需再用Euclidean算法计算C1^(-1),则

( C1^(-1) )^(-r) * C2^s = P mod n

另外,还有其它几种利用公共模数攻击的方法。总之,如果知道给定模数的一对e和d,一是有利于攻击者分解模数,一是有利于攻击者计算出其它成对的e’和d’,而无需分解模数。解决办法只有一个,那就是不要共享模数n。

RSA的小指数攻击。 有一种提高 RSA速度的建议是使公钥e取较小的值,这样会使加密变得易于实现,速度有所提高。但这样作是不安全的,对付办法就是e和d都取较大的值。

RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何,而且密码学界多数人士倾向于因子分解不是NPC问题。 RSA的缺点主要有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要 600 bits 以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET( Secure Electronic Transaction )协议中要求CA采用比特长的密钥,其他实体使用比特的密钥

首先,找出三个数,其中p,q是两个相异的质数,r是与(p-1)(q-1)互质的数这三个数便是privatekey。接着,找出m,使得rm==1mod(p-1)(q-1)这个m一定存在,因为r与(p-1)(q-1)互质,用辗转相除法就可以得到了再来,计算n=pqm,n这两个数便是publickey编码过程是,若资料为a,将其看成是一个大整数,假设a<n如果a>=n的话,就将a表成s进位(s<=n,通常取s=2^t),则每一位数均小於n,然後分段编码接下来,计算b==a^mmodn,(0<=b<n),b就是编码後的资料解码的过程是,计算c==b^rmodpq(0<=c<pq),於是乎,解码完毕等会会证明c和a其实是相等的

如果第三者进行窃听时,他会得到几个数:m,n(=pq),b他如果要解码的话,必须想办法得到r所以,他必须先对n作质因数分解要防止他分解,最有效的方法是找两个非常的大质数p,q,使第三者作因数分解时发生困难

<定理>
若p,q是相异质数,rm==1mod(p-1)(q-1),a是任意一个正整数b==a^mmodpq,c==b^rmodpq,
则c==amodpq

证明的过程,会用到费马小定理,叙述如下:
m是任一质数,n是任一整数,则n^m==nmodm 换另一句话说,如果n和m互质,则n^(m-1)==1modm)
运用一些基本的群论的知识,就可以很容易地证出费马小定理的 ><证明>
因为rm==1mod(p-1)(q-1),所以rm=k(p-1)(q-1)+1,其中k是整数,因为在modulo中是preserve乘法的x==ymodzandu==vmodz=>xu==yvmodz),
所以,c==b^r==(a^m)^r==a^(rm)==a^(k(p-1)(q-1)+1)modpq

1.如果a不是p的倍数,也不是q的倍数时,则a^(p-1)==1modp(费马小定理)=>a^(k(p-1)(q-1))==1modp,a^(q-1)==1modq(费马小定理)=>a^(k(p-1)(q-1))==1modq 所以p,q均能整除a^(k(p-1)(q-1))-1=>pq|a^(k(p-1)(q-1))-1,即a^(k(p-1)(q-1))==1modpq
=>c==a^(k(p-1)(q-1)+1)==amodpq

2.如果a是p的倍数,但不是q的倍数时,则a^(q-1)==1modq(费马小定理)
=>a^(k(p-1)(q-1))==1modq=>c==a^(k(p-1)(q-1)+1)==amodq=>q|c-a
因p|a
=>c==a^(k(p-1)(q-1)+1)==0modp
=>p|c-a所以,pq|c-a=>c==amodpq

3.如果a是q的倍数,但不是p的倍数时,证明同上

4.如果a同时是p和q的倍数时,则pq|a=>c==a^(k(p-1)(q-1)+1)==0modpq>pq|c-a
=>c==amodpq
Q.E.D.


这个定理说明a经过编码为b再经过解码为c时,a==cmodn(n=pq)....
但我们在做编码解码时,限制0<=a<n,0<=c<n,
所以这就是说a等於c,所以这个过程确实能做到编码解码的功能

 

RSA算法的C语言实现

#include <windows.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <math.h>

#include <time.h>

 

#define     DATALENGTH     350

#define     MLENGTH            10

#define     TESTNUM            20

#define     SKLENGTH   5

#define TEXTLENGTH  20

 

typedef signed char byteint[DATALENGTH];//-128 ->127

typedef signed char mtype[MLENGTH];

 

mtype Model[TESTNUM];

 

byteintONEVALUE,ZEROVALUE,TWOVALUE,EIGHTVALUE;

 

void InitInt(void);

void SetZero(byteint A);

void IntCpy(byteint A,byteint B);

int IntValid(byteint validtemp);

 

int IntCmp(byteint A,byteint B);

void Plus(byteint A,byteint B,byteint C);

void Substract(byteint SA,byteintSB,byteint SC);

void Multiply(byteint A,byteint B,byteintC);

void SetMode(byteint A,byteint B,byteintC,byteint D);

 

void IntRandom(byteint RandomA,int num);

 

void LoadInt(byteint A,mtype B);

void Mdata(void);

void TransBi(byteint B,signed charflag[400]);

 

int PowerMode(byteint A,byteint C,byteintD,signed char flag[400]);

 

int Prime(byteint Prm);

int ComputingPK(byteint Rvalue,byteintSK,byteint PK);

int StrToByt(char *str,byteint byt);

void BytToStr(byteint byt,char *str);

 

void PackInt(byteint A,int B);

 

byteint R,SK,PK,RsaKey;

 

extern int ShoutBlockingHook (void);

extern char szDataPath[128];

 

int RsaPrepare(byteint sk,byteintpk,byteint r)

{

      byteint p,q,Rvalue,buf1,buf2;

      

       Mdata();

       InitInt();

       Prime(p);

       Prime(q);

       Multiply(p,q,r);

       Substract(p,ONEVALUE,buf1);

       Substract(q,ONEVALUE,buf2);

       Multiply(buf1,buf2,Rvalue);

       ComputingPK(Rvalue,sk,pk);      

       returnTRUE;

}

 

int ReadRsaFile(byteint r,byteintpk,byteint sk)

{

       charfile[80],temp[100+1];

       sprintf(file,"%s\\sys\\rsa.dat",szDataPath);

      

       if(GetPrivateProfileString("RSA","R", "", temp,100, file)!=0)

              StrToByt(temp,r);  

       else

              returnFALSE;

       if(GetPrivateProfileString("RSA","PK", "", temp, 100, file)!=0)

              StrToByt(temp,pk);

       else

              returnFALSE;

       if(GetPrivateProfileString("RSA","SK", "", temp, 100, file)!=0)

              StrToByt(temp,sk);

       else

              returnFALSE;

 

       returnTRUE;

}

 

int WriteRsaFile(byteint r,byteintpk,byteint sk)

{

       charfile[80],temp[100+1];

       sprintf(file,"%s\\sys\\rsa.dat",szDataPath);

              memset(temp,0,100+1);

       BytToStr(r,temp);

       if(WritePrivateProfileString("RSA","R", temp, file)==0)

              returnFALSE;

       memset(temp,0,100+1);

       BytToStr(pk,temp);

       if(WritePrivateProfileString("RSA","PK", temp, file)==0)

              returnFALSE;

       memset(temp,0,100+1);

       BytToStr(sk,temp);

       if(WritePrivateProfileString("RSA","SK", temp, file)==0)

              returnFALSE;

 

       returnTRUE;        

}

 

 

int DecipherDesKey(byteint rsakey,byteintr,byteint sk,char *deskey)

{

       byteintbuf1;

       signedchar flag[400];

       Mdata();

       InitInt();

       TransBi(sk,flag);

       PowerMode(rsakey,r,buf1,flag);

   BytToStr(buf1,deskey);

     return 0;

}

 

void InitInt(void)

{

       SetZero(ONEVALUE);

       ONEVALUE[DATALENGTH-1]=1;

       SetZero(ZEROVALUE);

       SetZero(TWOVALUE);

       TWOVALUE[DATALENGTH-1]=2;

       SetZero(EIGHTVALUE);

       EIGHTVALUE[DATALENGTH-1]=8;

       //randomize();

       srand((unsigned)time(NULL));

}

 

void Multiply(byteint A,byteint B,byteintC)

{

       registeri,j,w;

       intX,Y,Z;

       intAvalid=0;

       intBvalid=0;

       while(A[Avalid]==0&&Avalid <DATALENGTH)

              Avalid++;

       while(B[Bvalid]==0&&Bvalid <DATALENGTH)

              Bvalid++;

       SetZero(C);

       for(i=DATALENGTH-1;i>=Avalid;i--)

       {

              for(j=DATALENGTH-1;j>=Bvalid;j--)

              {

                     X=A[i]*B[j];

                     Y=X/10;

                     Z=X-10*Y;

                     w=i+j-(DATALENGTH-1);

                     C[w]=C[w]+Z;

                     C[w-1]=C[w-1]+(C[w]/10)+Y;

                     C[w]=C[w]-(C[w]/10)*10;

              }

       }

}

 

void SetZero(byteint A)

{

       memset(A,0,DATALENGTH);

}

 

void IntCpy(byteint A,byteint B)

{

       memcpy(A,B,DATALENGTH);

}

 

void Plus(byteint A,byteint B,byteint C)

{

       registeri;

       intX,Y,Z,m,n,valid;

 

       m=IntValid(A);

       n=IntValid(B);

       valid=(m>n)? m+1:n+1;

       SetZero(C);

       for(i=DATALENGTH-1;i>=DATALENGTH -valid;i--)

       {

              X=A[i]+B[i];

              Y=X/10;

              Z=X-10*Y;

 

              C[i]=C[i]+Z;

              C[i-1]=C[i-1]+Y;

       }

}

 

void Substract(byteint SA,byteintSB,byteint SC)

{

       byteintbuf;

       registeri,j;

       intX;

 

       IntCpy(buf,SA);

       SetZero(SC);

 

       for(i=DATALENGTH-1;i>=0;i--)

       {

              if(buf[i]<SB[i]){

                     buf[i]+=10;

                     if(buf[i-1]>0)

                            (buf[i-1])--;

                     else{

                            j=i-1;

                            while(buf[j]==0)

                                   buf[j--]=9;

                            buf[j]--;

                     }

              }

              X=buf[i]-SB[i];

              SC[i]=X;

       }

}

 

int IntCmp(byteint A,byteint B)

{

       intstat;

 

       stat=memcmp(A,B,DATALENGTH);

       if(stat==0)

              return0;

       if(stat>0)

              return1;

       return-1;

}

 

int IntValid(byteint validtemp)

{

       registeri=0;

       while(validtemp[i]==0 && i<DATALENGTH)

              i++;

       returnDATALENGTH-i;

}

 

void SetMode(byteint A,byteint B,byteintC,byteint D)

{

       registeri,j,k;

 

       intvalid_1,valid_2,valid,sbits,cmpval;

       byteintbuf1,buf2;

 

       SetZero(D);

       IntCpy(C,A);

       valid_2=IntValid(B);

       while((cmpval=IntCmp(C,B))>0){

              valid_1=IntValid(C);

              valid=valid_1-valid_2;

              if(valid>0){

                     i=DATALENGTH-valid_1;

                     j=DATALENGTH-valid_2;

                     sbits=0;

                     for(k=j;k<DATALENGTH;k++){

                            if(C[i]>B[j])

                                   break;

                            if(C[i]<B[j]){

                                   sbits=1;

                                   break;

                            }

                            i++;j++;

                     }

                     valid=valid-sbits;

                     SetZero(buf1);

                     for(i=valid;i<DATALENGTH;i++){

                            j=i-valid;

                            buf1[j]=B[i];

                     }

              }

              else

                     IntCpy(buf1,B);

 

              D[DATALENGTH-1-valid]++;

              Substract(C,buf1,buf2);

              IntCpy(C,buf2);

       }

 

       if(cmpval==0){

              SetZero(C);

              D[DATALENGTH-1]++;

       }

}

 

void IntRandom(byteint RandomA,int num)

{

       inti;

       SetZero(RandomA);

       while(!(RandomA[DATALENGTH-1]% 2))

              RandomA[DATALENGTH-1]=rand()% 10;

 

       while(!RandomA[DATALENGTH-num])

              RandomA[DATALENGTH-num]=rand() % 10;

 

       i=DATALENGTH-2;

       while(i>=DATALENGTH-num +1)

              RandomA[i--]=rand()% 10;

}

 

void LoadInt(byteint A,mtype B)

{

       registeri,j;

 

       SetZero(A);

       i=DATALENGTH-1;

       j=MLENGTH-1;

       while(j>=0)

              A[i--]=B[j--];

}

 

void Mdata(void)

{

       registeri,j;

 

       intk=MLENGTH -2;

       memset(Model,0,TESTNUM*MLENGTH);

       for(i=0;i<TESTNUM;i++){

              for(j=MLENGTH-1;j>=k;j--)

                     Model[i][j]=rand()%10;

              k-=1;

       }

}

 

void TransBi(byteint B,signed charflag[400])

{

       byteintbuf;

       byteintresult;

       byteinttemp;

       registeri;

 

       memset(flag,0,400);

       i=399;

       IntCpy(buf,B);

       while(IntCmp(buf,ZEROVALUE)==1){

              ShoutBlockingHook();

              SetMode(buf,TWOVALUE,temp,result);

              flag[i]=temp[DATALENGTH-1];

              IntCpy(buf,result);

              i--;

       }

       flag[i]=-1;

}

 

int PowerMode(byteint A,byteint C,byteintD,signed char flag[400])

{

       byteintbuf;

       byteintresult;

       byteinttemp,P;

       registeri;

 

       IntCpy(temp,A);

       if(flag[399]==1)

              IntCpy(result,A);

       else

              IntCpy(result,ONEVALUE);

       i=398;

       while(flag[i]!=-1){

              ShoutBlockingHook();

              Multiply(temp,temp,buf);

              SetMode(buf,C,temp,P);

              if(flag[i]!=0){

                     Multiply(temp,result,buf);

                     SetMode(buf,C,result,P);

              }

              i--;

       }

       IntCpy(buf,C);

       IntCpy(D,result);

       Substract(buf,ONEVALUE,temp);

       if(IntCmp(result,ONEVALUE)==0)

              return1;

       if(IntCmp(result,temp)==0)

              return2;

       return0;

}

 

int Prime(byteint Prm)

{

       inti,k,ok,cnt=0;

       signedchar flag[400];

       byteintA,B,D,buf1,buf2;

       intpass=0,pass_2=0;

       while(1){

              ShoutBlockingHook();

              cnt++;

              IntRandom(B,MLENGTH);

              IntCpy(Prm,B);

              Substract(B,ONEVALUE,buf1);

              SetMode(buf1,TWOVALUE,buf2,B);

              TransBi(B,flag);

              ok=1;

              for(i=0;i<TESTNUM;i++){

                     LoadInt(A,Model[i]);

                     k=PowerMode(A,Prm,D,flag);

                     if(k!=1&&k!=2)

                            break;

                     if(k==2){

                            pass_2=1;

                     }

              }

              if(ok&& pass_2 ){

                     return0;

              }

       }

}

 

int ComputingPK(byteint Rvalue,byteintSK,byteint PK)

{

       registeri;

       byteintPA,PB,PC,buf,temp,buf2;

       SetZero(PK);

       while(1)

       {

              IntRandom(SK,SKLENGTH);

              IntCpy(PB,SK);

              IntCpy(PA,Rvalue);

              while(1){

                     ShoutBlockingHook();

                     SetMode(PA,PB,PC,PK);

                     i=IntCmp(PC,ONEVALUE);

                     if(i==0)

                            break;

                     i=IntCmp(PC,ZEROVALUE);

                     if(i==0){

                            i=-1;

                            break;

                     }

                     IntCpy(PA,PB);

                     IntCpy(PB,PC);

              }

              if(i==0)

                     break;

       }

       IntCpy(temp,ONEVALUE);

       IntCpy(PA,Rvalue);

       IntCpy(PB,SK);

 

       while(1){

              Multiply(PA,temp,buf);

              Plus(buf,ONEVALUE,buf2);

              SetMode(buf2,PB,buf,PK);

              if(IntCmp(buf,ZEROVALUE)==0)

                     break;

              Plus(temp,ONEVALUE,buf);

              IntCpy(temp,buf);

       }

       return1;

}

 

void PackInt(byteint A,int B)

{

       registeri=DATALENGTH-1;

 

       SetZero(A);

       while(B>0){

              A[i--]=B% 10;

              B=B/10;

       }

}

 

int StrToByt(char *str,byteint byt)

{

       unsignedint m;

              SetZero(byt);

       for(m=0;m<strlen(str);m++)

              byt[DATALENGTH-1-m]=str[strlen(str)-m-1]-'0';

       return1;

}

 

void BytToStr(byteint byt,char *str)

{

      unsigned int i=0,j=0;

      while(i<DATALENGTH&&byt[i]==0)i++;

      for(;i<DATALENGTH;i++,j++)

      {

             str[j] =byt[i]+'0';

      }

}

 

/*RSA.H*/

#define     DATALENGTH     350

signed char R[DATALENGTH],PK[DATALENGTH],RsaKey[DATALENGTH];

signed char SK[DATALENGTH];

unsigned char DesKey[9];

int RsaPrepare(signed char *sk,signed char*pk,signed char *r);

 

int ReadRsaFile(signed char *r,signed char*pk,signed char *sk);

int WriteRsaFile(signed char *r,signed char*pk,signed char *sk);

 

//int EncipherDesKey(char *deskey,signedchar *r,signed char *pk,signed char *rsakey);

int DecipherDesKey(signed char*rsakey,signed char *r,signed char *sk,char *deskey);

int StrToByt(char *str,signed char *byt);

void BytToStr(signed char *byt,char *str);

原创粉丝点击