四种古典密码的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 }