四种古典密码的C++实现(1)-----Hill密码

  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 }

 

posted @ 2017-04-12 19:38  nanashi  阅读(1918)  评论(0编辑  收藏  举报