1 //Hill密码
2 /*理解算法最重要,最好自己动手实现试试看,可以使用MFC写一个简单的交互界面*/
3
4 #include <iostream>
5 #include <string>
6 #include <memory.h>
7 #include <cstdlib>
8 #include <ctime>
9 #include <cstdio>
10 #include <cmath>
11 using namespace std;
12
13 //定义一些常变量
14 const int M = 26; //定义集合{a,b,...,z}的26个英文字母
15
16 //行和列均为5
17 const int ROW = 5;
18 const int COL = 5;
19
20 //定义5*5的加密矩阵
21 int K[ROW][COL];
22
23 //定义5*5的解密矩阵
24 int D[ROW][COL];
25
26 int P[ROW]; //明文单元
27 int C[ROW]; //密文单元
28 int F[ROW]; //密文解密后的单元
29
30 //三元组gcd(a,b) = ax + by = d
31 struct GCD
32 {
33 int x;
34 int y;
35 int d;
36 };
37
38 class Hill_Cipher
39 {
40 public:
41 //产生随机矩阵
42 void random_Matrix();
43 //求矩阵的行列式
44 int Det(int matrix[ROW][ROW],int row);
45
46 //求两个数的最大公约数
47 int gcd(int a,int b);
48
49 /*
50 *判断矩阵K是否在模26的情况下可逆
51 *因为矩阵在模26的情形下存在可逆矩阵的充分必要条件是
52 *gcd(det K,26) = 1
53 */
54 bool Inverse(int matrix[ROW][ROW]);
55
56 //矩阵相乘
57 void multiphy(int matrix[ROW][ROW],int p[ROW],int row);
58
59 //求出伴随矩阵
60 void adjoint_matrix(int matrix[ROW][ROW],int row);
61
62 //将明文加密为密文
63 string encryption(string plaintext);
64
65 //将密文解密为明文(为了辨识清楚,我们统一以小写字母作为明文,大写字母作为密文)
66 string deciphering(string ciphertext);
67
68 //欧几里得算法求模的逆
69 GCD extended_Euclid(int a,int b);
70
71 //模逆运算
72 int inverse(int a,int m);
73
74 //由于C++不存在负数取模的内置函数,现在自己设定一个
75 //定义一个模M的值
76 int Mod(int a);
77 };
78
79 void Hill_Cipher::random_Matrix()
80 {
81 int i,j;
82 for(i = 0;i < ROW;i++)
83 {
84 for(j = 0;j < COL;j++)
85 {
86 K[i][j] = rand() % 26; //产生一个5*5模26的矩阵
87 }
88 }
89
90 }
91
92 //求矩阵的行列式
93 int Hill_Cipher::Det(int matrix[ROW][ROW],int row)
94 {
95 int i,j;
96 int cofa[ROW][ROW]; //用于存放余子阵
97 int l; //l为所递归的余子阵的行
98 int p = 0,q = 0;
99 int sum=0;
100
101 //由于行和列相同(方阵),所以行列式的值一定存在,故不需要判断是否为方阵
102
103 //递归基
104 if(row == 1)
105 return matrix[0][0];
106 for(i = 0;i < row; i++)
107 {
108 for(l = 0;l < row - 1;l++)
109 {
110 if(l < i)
111 p=0;
112 else
113 p=1;
114 for(j = 0;j< row - 1;j++)
115 {
116 cofa[l][j] = matrix[l + p][j + 1];
117 }
118 }
119 //相当于(-1)^i
120 if(i % 2 == 0)
121 q=1;
122 else
123 q=(-1);
124 sum = sum + matrix[i][0] * q * Det(cofa,row - 1);
125 }
126 return sum;
127 }
128
129 //求两个数的最大公约数
130 int Hill_Cipher::gcd(int a,int b)
131 {
132 int temp;
133 //交换两个数的大小,使得a为较大数
134 if(a < b)
135 {
136 temp = a;
137 a = b;
138 b = temp;
139 }
140 while(a % b)
141 {
142 temp = b;
143 b = a % b;
144 a = temp;
145 }
146 return b;
147 }
148
149 /*
150 *判断矩阵K是否在模26的情况下可逆
151 *因为矩阵在模26的情形下存在可逆矩阵的充分必要条件是
152 *gcd(det K,26) = 1
153 */
154 bool Hill_Cipher::Inverse(int matrix[ROW][ROW])
155 {
156 if(gcd(Det(matrix,ROW),M) == 1)
157 return true;
158 else
159 return false;
160 }
161
162 void Hill_Cipher::multiphy(int matrix[ROW][ROW],int p[ROW],int row)
163 {
164 int i,j;
165 //先将密文单元清零
166 memset(C,0,sizeof(C));
167 for(i = 0;i < ROW;i++)
168 {
169 for(j = 0;j < ROW;j++)
170 {
171 C[i] += P[j] * K[j][i];
172 }
173 }
174 }
175
176 //将明文加密为密文
177 string Hill_Cipher::encryption(string plaintext)
178 {
179 int i;
180 string ciphertext;
181 //将字符串转化为明文数组
182 for(i = 0;i < ROW;i++)
183 {
184 P[i] = plaintext[i] - 'a';
185 }
186 multiphy(K,P,ROW);
187 //将密文数组转化为密文
188 for(i = 0;i < ROW;i++)
189 //这里先将其模26,再翻译为对应的字母
190 {
191 C[i] =Mod(C[i]);
192 ciphertext += C[i] + 'A';
193 }
194 return ciphertext;
195 }
196
197 //求出伴随矩阵
198 void Hill_Cipher::adjoint_matrix(int matrix[ROW][ROW],int row)
199 {
200 int i,j,k,l;
201 int p,q;
202 p = q = 0;
203 int temp[ROW][ROW];
204 for(i = 0;i < ROW;i++)
205 {
206 for(j = 0;j < ROW;j++)
207 {
208 for(k = 0;k < ROW - 1;k++)
209 {
210 if(k < i)
211 p = 0;
212 else
213 p = 1;
214 for(l = 0;l < ROW - 1;l++)
215 {
216 if(l < j)
217 q = 0;
218 else
219 q = 1;
220 temp[k][l] = matrix[k+p][l+q];
221 }
222 }
223 D[j][i] = (int)pow(-1,(double)i+j)*Det(temp,ROW-1);
224 D[j][i] = Mod(D[j][i]);
225 }
226 }
227 }
228
229 //将密文解密为明文(为了辨识清楚,我们统一以小写字母作为明文,大写字母作为密文)
230 string Hill_Cipher::deciphering(string ciphertext)
231 {
232 //求出矩阵的逆
233 string text;
234 int determinant = Det(K,ROW);
235 int inver = inverse(determinant,26);
236 adjoint_matrix(K,ROW); //伴随矩阵
237 cout << "行列式的值: " << determinant << endl;
238 int i,j;
239 memset(F,0,sizeof(F));
240 for(i = 0;i < ROW;i++)
241 {
242 for(j = 0;j < ROW;j++)
243 {
244 F[i] += C[j] * D[j][i];
245 }
246 F[i] *= inver;
247 F[i] = Mod(F[i]); //算到的结果要模去26
248 }
249 for(i = 0;i < ROW;i++)
250 text += F[i] + 'a';
251 return text;
252 }
253
254 GCD Hill_Cipher::extended_Euclid(int a,int b)
255 {
256 GCD aa,bb;
257 if(b == 0)
258 {
259 aa.x = 1;
260 aa.y = 0;
261 aa.d = a;
262 return aa;
263 }
264 else
265 {
266 bb = extended_Euclid(b,a%b);
267 aa.x = bb.y;
268 aa.y = bb.x - (a / b) * bb.y;
269 aa.d = bb.d;
270 }
271 return aa;
272 }
273
274 int Hill_Cipher::inverse(int a,int m)
275 {
276 GCD aa;
277 aa = extended_Euclid(a,m);
278 return aa.x;
279 }
280
281 int Hill_Cipher::Mod(int a)
282 {
283 return a >= 0 ? a % M : (M + a % M);
284 }
285
286 int main()
287 {
288 int i,j;
289 Hill_Cipher hh;
290 cout << "使用希尔密码进行消息的加解密:" << endl;
291
292 //srand()函数产生一个以当前时间开始的随机种子.以保证每次产生的随机数矩阵都不相同
293 srand((unsigned)time(0));
294 hh.random_Matrix();
295 while(!hh.Inverse(K))
296 {
297 hh.random_Matrix();
298 }
299 cout << "随机产生5*5的矩阵:" << endl;
300 for(i = 0;i < ROW;i++)
301 {
302 for(j = 0;j < COL;j++)
303 {
304 printf("%2d ",K[i][j]);
305 }
306 cout << endl;
307 }
308 cout << "该矩阵模26可逆,因此可以作为密钥." << endl;
309 cout << endl;
310
311 //利用所选密钥,对给定的5元明文信息进行加解密
312 string plaintext,ciphertext;
313 cout << "请输入5元明文信息:" << endl;
314 cin >> plaintext;
315 ciphertext = hh.encryption(plaintext);
316 cout << endl;
317 cout << "该明文通过希尔密码法加密过后,输出的密文消息为:" << endl;
318 cout << ciphertext << endl;
319 cout << endl;
320
321 cout << "***输入0:退出 ***" << endl;
322 cout << "***输入1:查看明文空间对***" << endl;
323 cout << "***输入2:查看密文空间对***" << endl;
324 cout << "***输入3:查看密钥 ***" << endl;
325 cout << "***输入4:将消息解密 ***" << endl;
326 cout << "***输入5:查看菜单 ***" << endl;
327
328 char c;
329 while(cin >> c)
330 {
331 if(c == '0')
332 {
333 cout << endl;
334 cout << "退出" << endl;
335 break;
336 }
337 else if(c == '1')
338 {
339 cout << "明文空间:" << endl;
340 for(i = 0;i < ROW;i++)
341 cout << P[i] << " ";
342 cout << endl;
343 cout << endl;
344 }
345 else if(c == '2')
346 {
347 cout << "密文空间:" << endl;
348 for(i = 0;i < ROW;i++)
349 cout << C[i] << " ";
350 cout << endl;
351 cout << endl;
352 }
353 else if(c == '3')
354 {
355 cout << "密钥:" << endl;
356 for(i = 0;i < ROW;i++)
357 {
358 for(j = 0;j < ROW;j++)
359 {
360 printf("%2d ",K[i][j]);
361 }
362 cout << endl;
363 }
364 cout << endl;
365 }
366 else if(c == '4')
367 {
368 hh.adjoint_matrix(K,ROW);
369 string ss;
370 ss = hh.deciphering(ciphertext);
371 cout << "该密文解密过后,显示的原来的明文消息:" << endl;
372 cout << ss << endl;
373 cout << endl;
374 }
375 else
376 {
377 cout << "***输入0:退出 ***" << endl;
378 cout << "***输入1:查看明文空间对***" << endl;
379 cout << "***输入2:查看密文空间对***" << endl;
380 cout << "***输入3:查看密钥 ***" << endl;
381 cout << "***输入4:将消息解密 ***" << endl;
382 cout << "***输入5:查看菜单 ***" << endl;
383 }
384 }
385 return 0;
386 }