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

小素数情况下的实现:

 

  1. #include<stdio.h> 
  2. #include<stdlib.h> 
  3. #include<time.h> 
  4. typedef long long ULL; 
  5.  
  6. ULL extended_eculid(ULL a , ULL b, ULL &s, ULL &t)//扩展Eculid定理 
  7.     if(b == 0) 
  8.     { 
  9.         s = 1; 
  10.         t = 0; 
  11.         return a; 
  12.     } 
  13.     ULL d, x, y; 
  14.     d = extended_eculid(b,a % b,x,y); 
  15.     s = y; 
  16.     t = x - a/b*y; 
  17.     return d; 
  18.  
  19. ULL Squ_Mul(ULL a, ULL b, ULL n)//模重复平方法求(a^b)mod n 
  20.     ULL ans; 
  21.     ans = 1; 
  22.     while(b!=0) 
  23.     { 
  24.         if(b&1==1) 
  25.             ans = (ans*a)%n; 
  26.         a = (a*a)%n; 
  27.         b>>=1; 
  28.     } 
  29.     return ans; 
  30.  
  31. int Miller_Rabin(ULL n,int k)//Miller_Rabin素性测试 
  32.     ULL m = n - 1; 
  33.     int i; 
  34.     while((m%2)!=1) 
  35.         m>>=1; 
  36.     ULL a; 
  37.     while(1) 
  38.     { 
  39.         time_t random = time(NULL);  
  40.         a = random%(n-1); 
  41.         if(a!=0 && a!=1) 
  42.             break
  43.     } 
  44.     ULL b = Squ_Mul(a,m,n); 
  45.     if(b == 1) 
  46.         return 1; 
  47.     for(i = 0; i < k; i++) 
  48.     { 
  49.         if( b == n -1) 
  50.         { 
  51.             return 1; 
  52.         } 
  53.         else 
  54.         { 
  55.             b = ((b%n)*(b%n))%n; 
  56.         } 
  57.     } 
  58.     return 0; 
  59.  
  60. int menu()//菜单 
  61.     int select=1; 
  62.     printf("***********RSA**********\n"); 
  63.     printf("1 生成素数对和密钥对\n"); 
  64.     printf("2 加密\n"); 
  65.     printf("3 解密\n"); 
  66.     printf("0 退出\n"); 
  67.     printf("***********************\n"); 
  68.     while(1) 
  69.     { 
  70.         printf("请选择:"); 
  71.         scanf("%d",&select); 
  72.         if(select == 0 || select == 1 || select == 2 || select == 3) 
  73.             return select; 
  74.     } 
  75.  
  76.  
  77. ULL GenPrime( ULL &p, int bitNum,int k)//生成素数 
  78. //  p = 1; 
  79. //  p |= (1<<(bitNum -1)); 
  80.     time_t random = time(NULL);  
  81.     int count = 100; 
  82.     ULL con = 1<<bitNum; 
  83.     if(p%2==0) 
  84.         p = (p+1)%con; 
  85.     while(count) 
  86.     { 
  87.         if(Miller_Rabin(p,k)) 
  88.             return 1;        
  89.         p = (p+time(NULL))%con; 
  90.         p |= (1<<(bitNum -1)); 
  91.         if(p%2==0) 
  92.             p = (p+1)%con; 
  93. //      p = (p+2)%con; 
  94.         if(p == 0 || p == 1) 
  95.             p = 3; 
  96.         count--; 
  97.     } 
  98.     return 0; 
  99.  
  100. void GenPQ(ULL &p, ULL &q) 
  101.     int BitNumP = 10,BitNumQ = 10; 
  102.     printf("请输入要生成的素数 P 的bit位数(4<=bit<31):"); 
  103.     scanf("%d",&BitNumP); 
  104.     p = q = 3; 
  105.     p|=1<<(BitNumP-1); 
  106.     if(GenPrime(p,BitNumP,5) == 0) 
  107.     { 
  108.         printf("没有找到素数p\n"); 
  109.         exit(0); 
  110.     } 
  111.     printf("请输入要生成的素数 Q 的bit位数(4<=bit<31):"); 
  112.     scanf("%d",&BitNumQ); 
  113.     q|=1<<(BitNumQ-1); 
  114.     int count = 100; 
  115.     while(count) 
  116.     { 
  117.         if(GenPrime(q,BitNumQ,5)==0) 
  118.         { 
  119.             printf("没有找到素数q\n"); 
  120.             exit(0); 
  121.         } 
  122.         if(q!=p) 
  123.             break
  124.          else 
  125.              q = q + 2; 
  126.         count--; 
  127.     } 
  128.     if(count == 0) 
  129.     { 
  130.         printf("没有找到素数q\n"); 
  131.         exit(0); 
  132.     } 
  133.  
  134. int main() 
  135.     int select = menu(); 
  136.     ULL m,n,c; 
  137.     ULL Euler_N; 
  138.     ULL e,d=0; 
  139.     while(select) 
  140.     { 
  141.     switch (select) 
  142.     { 
  143.     case 1: 
  144.     { 
  145.         ULL p,q; 
  146.         p = q = 0; 
  147.         GenPQ(p,q);//生成P Q 
  148.         n = p*q; 
  149.          
  150.         Euler_N = (p-1)*(q-1);//计算欧拉函数值 
  151.         time_t random = time(NULL);  
  152.         int count = 100; 
  153.         ULL t = 0; 
  154.         for(e = 3; e < Euler_N; e+=2) 
  155.         {                             
  156.             if(extended_eculid(e,Euler_N,d,t) == 1) 
  157.                 break
  158.         } 
  159.         d = (d+Euler_N)%Euler_N; 
  160.         if(e>=Euler_N) 
  161.         { 
  162.             printf("没有合适的e\n"); 
  163.             exit(0); 
  164.         } 
  165.         printf(" p= %lld q= %lld n= %lld e= %lld d= %lld \n",p,q,n,e,d); 
  166. /*      while(count) 
  167.         { 
  168.             e = time(0); 
  169.             e|= 1; 
  170.             e = e%Euler_N; 
  171.             if(e!=0 && e!=1 && extended_eculid(e,Euler_N,d,t) == 1) 
  172.             { 
  173.                 break; 
  174.             } 
  175.             count--; 
  176.         }  
  177.         if(count==0) 
  178.         { 
  179.             printf("没有e\n"); 
  180.             exit(0); 
  181.         }*/ 
  182.         break
  183.         } 
  184.         case 2:                         //用公钥加密 
  185.         { 
  186.             printf("导入公钥 N :"); 
  187.             scanf("%lld",&n); 
  188.             printf(" n= %lld ",n); 
  189.             printf("导入公钥 E :"); 
  190.             scanf("%lld",&e); 
  191.             printf(" e= %lld \n",e); 
  192.             ULL leftLen = n/(1<<30);//此处主要是控制m不能太小,否则得到的C太大,计算时会溢出,出错 
  193.             ULL rightLen = (n<(1<<30))?n:(1<<30);//m也不能太大,否则计算m^e mod n时,m*m会有问题 
  194.             printf("请输入明文(%lld<m<%lld) :",leftLen,rightLen); 
  195.             scanf("%lld",&m); 
  196.             if(m>=rightLen || m<=leftLen) 
  197.             { 
  198.                 printf("明文分组不符合要求!\n"); 
  199.                 break
  200.             } 
  201.          
  202.              
  203.             printf(" m=%lld ",m); 
  204.             c = Squ_Mul(m,e,n); 
  205.             printf(" c= %lld \n",c); 
  206.  
  207.             break
  208.         } 
  209.         case 3:                             //用私钥解密 
  210.         { 
  211.             printf("导入公钥 N :"); 
  212.             scanf("%lld",&n); 
  213.             printf(" n= %lld ",n); 
  214.              
  215.             printf("导入私钥 D :"); 
  216.             scanf("%lld",&d); 
  217.             printf(" d= %lld \n",d); 
  218.              
  219.             printf("请输入密文 :");       
  220.             scanf("%lld",&c); 
  221.          
  222.             printf(" c=%lld ",c); 
  223.             m = Squ_Mul(c,d,n); 
  224.             printf(" m= %lld \n",m); 
  225.             break
  226.         } 
  227.         default:break
  228.     } 
  229.     select = menu(); 
  230.     } 
  231.     return 0;