密码学---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 }