密碼學---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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM