密码学---RSA密码的C++实现

1 //RSA密码
  2 /*理解算法最重要,最好自己动手实现试试看,可以使用MFC写一个简单的交互界面*/
  3 
  4 #include <iostream>
  5 #include <cstdlib>
  6 #include <ctime>
  7 #include <cstring>
  8 using namespace std;
  9 //RSA算法所需参数
 10 typedef struct  RSA_PARAM_Tag
 11 {
 12     unsigned __int64    p, q;   //两个素数,不参与加密解密运算
 13     unsigned __int64    f;      //f=(p-1)*(q-1),不参与加密解密运算
 14     unsigned __int64    n, e;   //公匙,n=p*q,gcd(e,f)=1
 15     unsigned __int64    d;      //私匙,e*d=1 (mod f),gcd(n,d)=1
 16     unsigned __int64    s;      //块长,满足2^s<=n的最大的s,即log2(n)
 17 } RSA_PARAM;
 18 //小素数表
 19 const static long       g_PrimeTable[]=
 20 {
 21     3,5,7,11,13,17,19,23,29,31,37,41,43,
 22     47,53,59,61,67,71,73,79,83,89,97
 23 };
 24 const static long       g_PrimeCount=sizeof(g_PrimeTable) / sizeof(long);const unsigned __int64  multiplier=12747293821;
 25 const unsigned __int64  adder=1343545677842234541;//随机数类
 26 class                   RandNumber
 27 {
 28 private:
 29     unsigned __int64    randSeed;
 30 public:
 31     RandNumber(unsigned __int64 s=0);
 32     unsigned __int64    Random(unsigned __int64 n);
 33 };
 34 RandNumber::RandNumber(unsigned __int64 s)
 35 {
 36     if(!s)
 37     {
 38         randSeed= (unsigned __int64)time(NULL);
 39     }
 40     else
 41     {
 42         randSeed=s;
 43     }
 44 }
 45 unsigned __int64 RandNumber::Random(unsigned __int64 n)
 46 {
 47     randSeed=multiplier * randSeed + adder;
 48     return randSeed % n;
 49 }static RandNumber   g_Rnd;
 50 
 51 //模乘运算,返回值 x=a*b mod n
 52 inline unsigned __int64 MulMod(unsigned __int64 a, unsigned __int64 b, unsigned __int64 n)
 53 {
 54     return a * b % n;
 55 }
 56 
 57 //模幂运算,返回值 x=base^pow mod n
 58 unsigned __int64 PowMod(unsigned __int64 &base, unsigned __int64 &pow, unsigned __int64 &n)
 59 {
 60     unsigned __int64    a=base, b=pow, c=1;
 61     while(b)
 62     {
 63         while(!(b & 1))
 64         {
 65             b>>=1;            //a=a * a % n;    //函数看起来可以处理64位的整数,但由于这里a*a在a>=2^32时已经造成了溢出,因此实际处理范围没有64位
 66             a=MulMod(a, a, n);
 67         }        b--;        //c=a * c % n;        //这里也会溢出,若把64位整数拆为两个32位整数不知是否可以解决这个问题。
 68         c=MulMod(a, c, n);
 69     }    return c;
 70 }
 71 /*
 72 Rabin-Miller素数测试,通过测试返回1,否则返回0。
 73 n是待测素数。
 74 */
 75 long RabinMillerKnl(unsigned __int64 &n)
 76 {
 77     unsigned __int64    b, m, j, v, i;
 78     m=n - 1;
 79     j=0;    //计算出m、j,使得n-1=m*2^j,其中m是正奇数,j是非负整数
 80     while(!(m & 1))
 81     {
 82         ++j;
 83         m>>=1;
 84     }    //随机取一个b,2<=b<n-1
 85     b=2 + g_Rnd.Random(n - 3);    //算v=b^m mod n
 86     v=PowMod(b, m, n);    //如果v==1,通过测试
 87     if(v == 1)
 88     {
 89         return 1;
 90     }    //令i=1
 91     i=1;    //v=n-1,通过测试
 92     while(v != n - 1)
 93     {
 94         //i==l,非素数,结束
 95         if(i == j)
 96         {
 97             return 0;
 98         }        //v=v^2 mod n,i=i+1
 99         unsigned long long xxx;
100         int xxxx = 2;
101         xxx = xxxx;
102         v = PowMod(v, xxx, n);
103         ++i;        //循环到5
104     }    return 1;
105 }
106 /*
107 Rabin-Miller素数测试,循环调用核心loop次
108 全部通过返回1,否则返回0
109 */
110 long RabinMiller(unsigned __int64 &n, long loop)
111 {
112     //用小素数筛选一次,提高效率
113     for(long i=0; i < g_PrimeCount; i++)
114     {
115         if(n % g_PrimeTable[i] == 0)
116         {
117             return 0;
118         }
119     }    //循环调用Rabin-Miller测试loop次,使得非素数通过测试的概率降为(1/4)^loop
120     for(long i=0; i < loop; i++)
121     {
122         if(!RabinMillerKnl(n))
123         {
124             return 0;
125         }
126     }    return 1;
127 }/*
128 随机生成一个bits位(二进制位)的素数,最多32位
129 */
130 unsigned __int64 RandomPrime(char bits)
131 {
132     unsigned __int64    base;
133     do
134     {
135         base= (unsigned long)1 << (bits - 1);   //保证最高位是1
136         base+=g_Rnd.Random(base);               //再加上一个随机数
137         base|=1;    //保证最低位是1,即保证是奇数
138     } while(!RabinMiller(base, 30));    //进行拉宾-米勒测试30次
139     return base;    //全部通过认为是素数
140 }/*
141 欧几里得法求最大公约数
142 */
143 unsigned __int64 EuclidGcd(unsigned __int64 &p, unsigned __int64 &q)
144 {
145     unsigned __int64    a=p > q ? p : q;
146     unsigned __int64    b=p < q ? p : q;
147     unsigned __int64    t;
148     if(p == q)
149     {
150         return p;   //两数相等,最大公约数就是本身
151     }
152     else
153     {
154         while(b)    //辗转相除法,gcd(a,b)=gcd(b,a-qb)
155         {
156             a=a % b;
157             t=a;
158             a=b;
159             b=t;
160         }        return a;
161     }
162 }/*
163 Stein法求最大公约数
164 */
165 unsigned __int64 SteinGcd(unsigned __int64 &p, unsigned __int64 &q)
166 {
167     unsigned __int64    a=p > q ? p : q;
168     unsigned __int64    b=p < q ? p : q;
169     unsigned __int64    t, r=1;
170     if(p == q)
171     {
172         return p;           //两数相等,最大公约数就是本身
173     }
174     else
175     {
176         while((!(a & 1)) && (!(b & 1)))
177         {
178             r<<=1;          //a、b为偶数时,gcd(a,b)=2*gcd(a/2,b/2)
179             a>>=1;
180             b>>=1;
181         }        if(!(a & 1))
182         {
183             t=a;            //a为偶数,交换a,b
184             a=b;
185             b=t;
186         }        do
187         {
188             while(!(b & 1))
189             {
190                 b>>=1;      //b为偶数,a为奇数时,gcd(b,a)=gcd(b/2,a)
191             }            if(b < a)
192             {
193                 t=a;        //b小于a,交换a,b
194                 a=b;
195                 b=t;
196             }            b=(b - a) >> 1; //b、a都是奇数,gcd(b,a)=gcd((b-a)/2,a)
197         } while(b);
198         return r * a;
199     }
200 }/*
201 已知a、b,求x,满足a*x =1 (mod b)
202 相当于求解a*x-b*y=1的最小整数解
203 */
204 unsigned __int64 Euclid(unsigned __int64 &a, unsigned __int64 &b)
205 {
206     unsigned __int64    m, e, i, j, x, y;
207     long                xx, yy;
208     m=b;e=a;x=0;y=1;xx=1;yy=1;
209     while(e)
210     {
211         i=m / e;j=m % e;
212         m=e;e=j;j=y;y*=i;
213         if(xx == yy)
214         {
215             if(x > y)
216                 y=x - y;
217             else{
218                 y-=x;
219                 yy=0;
220             }
221         }
222         else
223         {
224             y+=x;
225             xx=1 - xx;
226             yy=1 - yy;
227         }        x=j;
228     }    
229     if(xx == 0)
230         x=b - x;
231     return x;
232 }/*
233 随机产生一个RSA加密参数
234 */
235 RSA_PARAM RsaGetParam(void)
236 {
237     RSA_PARAM           Rsa={ 0 };
238     unsigned __int64    t;
239     Rsa.p=RandomPrime(16);          //随机生成两个素数
240     Rsa.q=RandomPrime(16);
241     Rsa.n=Rsa.p * Rsa.q;
242     Rsa.f=(Rsa.p - 1) * (Rsa.q - 1);
243     do
244     {
245         Rsa.e=g_Rnd.Random(65536);  //小于2^16,65536=2^16
246         Rsa.e|=1;                   //保证最低位是1,即保证是奇数,因f一定是偶数,要互素,只能是奇数
247     } while(SteinGcd(Rsa.e, Rsa.f) != 1);    
248     Rsa.d=Euclid(Rsa.e, Rsa.f);
249     Rsa.s=0;
250     t=Rsa.n >> 1;
251     while(t)
252     {
253         Rsa.s++;                    //s=log2(n)
254         t>>=1;
255     }    
256     return Rsa;
257 }/*
258 拉宾-米勒测试
259 */
260 void TestRM(void)
261 {
262     unsigned long   k=0;
263     cout << "拉宾-米勒测试\n" << endl;
264     for(unsigned __int64 i=4197900001; i < 4198000000; i+=2)
265     {
266         if(RabinMiller(i, 30))
267         {
268             k++;
269             cout << i << endl;
270         }
271     }    cout << "Total: " << k << endl;
272 }/*
273  RSA加密解密
274  */
275 void TestRSA(void)
276 {
277     cout << "请输入待加密的内容(支持字母、汉字、以及其他符号和下划线):\n";
278     RSA_PARAM           r;
279     string in_1;
280     //char  pSrc[123];
281 /*    char *pSrc;
282     getline(cin, in_1);
283     getline(cin, in_1);*/
284 //    char pSrc[100];
285     fflush(stdin);
286     char pSrc[100];
287     scanf("%[^\n]s",pSrc);
288     //scanf("%[^\n]s",pSrc);
289     //puts(pSrc);
290     //fflush(stdin);
291 //    pSrc = const_cast<char *>(in_1.data());
292 
293     const unsigned long n = sizeof(pSrc);
294     unsigned char       *q, pDec[n];
295     unsigned __int64    pEnc[n];
296     r = RsaGetParam();
297     cout << "---------------------------------\n";
298     cout << "p=" << r.p << endl;
299     cout << "q=" << r.q << endl;
300     cout << "f=(p-1)*(q-1)=" << r.f << endl;
301     cout << "n=p*q=" << r.n << endl;
302     cout << "e=" << r.e << endl;
303     cout << "d=" << r.d << endl;
304     cout << "s=" << r.s << endl;
305     cout << "---------------------------------\n";
306     
307     q = (unsigned char*)pSrc;
308     //cout<<q<<"&&&&&\n";//=================
309     cout << "Encode:\n";
310     for (unsigned long i = 0; i < n; i++)
311     {
312         unsigned long long xxx;
313         int xxxx = q[i];
314         xxx = xxxx;
315         pEnc[i] = PowMod(xxx, r.e, r.n);
316         cout << hex << pEnc[i] << " ";
317     }    
318     cout << "\n\n";
319     
320     cout << "Decode:\n";
321     for (unsigned long i = 0; i < n; i++)
322     {
323         pDec[i] = PowMod(pEnc[i], r.d, r.n);
324         cout << hex << (unsigned long)pDec[i] << " ";
325     }    
326     cout << "\n\n";
327     
328     cout << "解密后的文档:\n";
329     cout << (char *)pDec << endl;
330 }/* */
331 int main(void)
332 {
333     cout << "Start~!\n\n";
334     char inorder;
335     /*cin >> inorder;
336     fflush(stdin);
337     if (inorder == '1')
338         TestRSA();
339     //    TestRSA();*/
340     cout << "如果想进行下一个加密过程,请输入n键,退出请输入q键:\n\n";
341     while (cin >> inorder && inorder == 'n')
342     {
343         system("cls");
344         TestRSA();
345         cout << "如果想进行下一个加密过程,请输入n键,退出请输入q键:\n\n";
346     }
347     if (inorder == 'q')
348         cout << "谢谢使用~!下次再见 > . < ~\n";
349     return 0;
350 }