1、 实验目的
通过五种加密解密算法的分析与设计,用高级语言实现加密解密过程。通过实验过程理解系统中加密解密的基本思想和实现方法。
2、 实验基本原理与方法
①单字母替换加密方法——恺撒密码
加密方法是把英文字母按字母表的顺序编号作为明文,将密钥定为m,加密算法为将明文加上密钥m,得到密码表,通过相反的过程由密文得到明文。
②单字母替换加密方法——字母倒排序
在加密、解密的过程中明文和密文按照字母表的顺序倒排对应,即A对应Z,B对应Y。
③单字母替换加密方法——单表置换密码
由密钥Key构造字符置换表,完成加密和解密过程。
④多字母替换加密方法——维吉利亚密码
假设明文m=m1 m2 m3 … mn;密钥k=k1k2 k3 … kn,对应密文c=c1 c2 c3 … cn,密文为:ci=(mi+ki )mod 26 ,26个字母的序号依次为0~25,ci , mi ,,ki是分别是密文明文密钥中第i个字母的序号。
⑤转换加密方法
通过将明文每m个字符一组按顺序分为若干个字符串,再按照先列后行形成密文,并分析给出解密的方法。或者通过给出一个密钥字符串,将明文按密钥字符串长度按顺序分为若干组字符串,再按照密钥字符串各个字符的顺序形成密文,并分析给出解密的方法。
3 具体实现方法:
① 实验方案简述:
本次实验选择用高级语言C#完成,使用面向对象的思想编程,一来对算法实现了较好的封装,使程序安全性提高,同时通过采用C#Web窗体编程框架,设计了较为直观方面的交互页面,并且对程序输入进行输入合法性验证,提高了程序的用户体验,也保证了程序的稳定运行。本实验根据上述实验的基本原理与方法设计程序算法并予以实现,分别实现了凯撒算法、字母倒排序、单表置换、维吉利亚密码和转化加密方法的加密解密。
② 实验技术路线:
1 凯撒算法
凯撒算法较为简单只是按照字母表按照密钥移动形成密文或解密显现原文,但是得注意 ,.\:?等符号的出现,所以List长度为32同时注意边界的判断别入?的加密和a的解密,以及密文中字母大小写部分,所以在进行加密或解密前可以将所有字母转换成与List对应的大学,并统一以大写字母输出。
2 字母倒排序法
字母倒排序法也是较为简单的一种加密解密算法,建立字母表List并将输入按照字母表对应顺讯输出即可。
3 单表置换法
单表置换法与前两种算法的主要区别在于,单表置换法的对应表是先将密钥填入进去再将剩余的字母表字母按照字母表顺序填入,之后以之与字母表对应生成密文或对密文进行解密。该方法注意密钥中可能会出现相同的字母所以要去除密钥中相同字母再生成对应的密文表。
4 维吉利亚算法
维吉利亚算法是由两个表生成密文,第一个是密文中字母对应字母表中的顺序,第二个是按照密钥顺序构建长度等于密文的参照表,然后由m+n%26得出对应的密文对应List顺讯,解密过程先判断每个字母对应两个表的位置上面的字母在List中的位次大小,作出是否给密文对应表字母对应List顺序+26再减去密钥对应表中对应List位次,即为原文该位置上的字母对应List上的位次。解密过程较加密过程复杂,起初是比较懵的,然后百度了一下该类问题得解决原理,写出了算法并进行测试,没有问题,所以通过。
5 转换加密方法
转换加密方法有两种,第一种是根据int类型密钥,将输入信息分割成密钥长度的片段并将其进行倒叙排序,然后连接片段并输出,解密过程可以是和加密过程一样的操作进行解密,该过程比较简单,但是得注意不能讲输入信息全部截断成等于密钥长度的片段的情况,这里我使用了栈结构,同时加判断如果栈的长度等于密钥长度将其输出到新的片段字符串,并对不能刚好截成等于密钥长度的片段进行判断标记单独处理。
第二种方法可以设置成第一种方法的重载,我理解的第二种方法是根据密钥长度将输入信息拆分成等于密钥长度的片段,然后将每个片段按照密钥的对应List序号进行排序,之后将各个片段连接并输出。该方法由于涉及将拆分的片段密钥对用List顺序排列,所以我将不能全部拆分成等于密钥长度的片段给其后面补不常见的字符‘!’,进行排序后再将‘!’删除。同时注意密钥中不可以有相同的字符出现,而且解密过程与加密算法是不一样的。其中该过程调试修改了多次,虽然实现了正确的加密解密,但是感觉算法过程比较复杂,在加密过程,先将List字母顺序对应shunxu数组位置,List顺序字母在key出现的位置对应shunxu数组的值,然后将shunxu转换成按照List字母出现顺序的nshunxu,如key=”adbc”,shunxu=0231,nshunxu=0312,再令shuxun=nshunxu。然后按照位置递进,在每个片段截取对应shunxu数组的值。解密时,不需要令shuxun=nshunxu,但是要将不能全部拆分成等于密钥长度的片段还原成带有“!”的加密状态,否则会出现错误。
1 //凯撒算法 2 public string Caesar(int xuanze, string psd, int key) 3 { 4 string List = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ,.\\:?"; 5 psd = psd.ToUpper(); 6 char[] miwen1 = new char[psd.Length]; 7 string miwen; 8 int i = 0; 9 if (xuanze == 1) 10 { 11 foreach (char e in psd) 12 { 13 int m = List.IndexOf(e); 14 15 if (m + key < List.Length) 16 { 17 string mm = List.Substring(m + key, 1); 18 miwen1[i] = Char.Parse(mm); 19 i++; 20 } 21 else 22 { 23 string mm = List.Substring((m + key) - List.Length, 1); 24 miwen1[i] = Char.Parse(mm); 25 i++; 26 } 27 28 } 29 miwen = string.Join("", miwen1); 30 Console.WriteLine(psd); 31 return miwen; 32 } 33 else 34 { 35 foreach (char e in psd) 36 { 37 int m = List.IndexOf(e); 38 if (m - key < 0) 39 { 40 string mm = List.Substring(m + 32 - key, 1); 41 miwen1[i] = Char.Parse(mm); 42 i++; 43 } 44 else 45 { 46 string mm = List.Substring((m - key), 1); 47 miwen1[i] = Char.Parse(mm); 48 i++; 49 } 50 } 51 miwen = string.Join("", miwen1); 52 return miwen; 53 } 54 } 55 //字母倒排序 56 public string Ainversion(int xuanze, string psd) 57 { 58 string List = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 59 psd = psd.ToUpper(); 60 char[] miwen1 = new char[psd.Length]; 61 string miwen; 62 int i = 0; 63 if (xuanze == 1) 64 { 65 foreach (char e in psd) 66 { 67 int m = List.IndexOf(e); 68 string mm = List.Substring(List.Length - m - 1, 1); 69 miwen1[i] = Char.Parse(mm); 70 i++; 71 } 72 miwen = string.Join("", miwen1); 73 return miwen; 74 } 75 else 76 { 77 foreach (char e in psd) 78 { 79 int m = List.IndexOf(e); 80 string mm = List.Substring(List.Length - m - 1, 1); 81 miwen1[i] = Char.Parse(mm); 82 i++; 83 } 84 miwen = string.Join("", miwen1); 85 return miwen; 86 } 87 } 88 //单表置换密码 89 public string STReplace(int xuanze, string psd, string key) 90 { 91 string List = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 92 //先构建一个对应的表吧 93 string NList; 94 char[] nList = new char[List.Length]; 95 key = key.ToUpper(); 96 int j = 0; 97 foreach (char e in List) 98 { 99 if (key.IndexOf(e) == -1) 100 { 101 nList[j] = e; 102 j++; 103 } 104 } 105 string sList = string.Join("", nList); 106 string LList = sList.Substring(0, j); 107 //Console.WriteLine(LList); 108 //LList没有问题了,但是key中还存在重复的值 109 string nkey = ""; 110 foreach (char e in key) 111 { 112 if (nkey.IndexOf(e) == -1) 113 { 114 nkey += e; 115 } 116 } 117 NList = nkey + LList; 118 //Console.Write(NList); 119 120 psd = psd.ToUpper(); 121 char[] miwen1 = new char[psd.Length]; 122 string miwen; 123 int i = 0; 124 if (xuanze == 1) 125 { 126 foreach (char e in psd) 127 { 128 int m = List.IndexOf(e); 129 string mm = NList.Substring(m, 1); 130 miwen1[i] = Char.Parse(mm); 131 i++; 132 } 133 miwen = string.Join("", miwen1); 134 return miwen; 135 } 136 else 137 { 138 foreach (char e in psd) 139 { 140 int m = NList.IndexOf(e); 141 string mm = List.Substring(m, 1); 142 miwen1[i] = Char.Parse(mm); 143 i++; 144 } 145 miwen = string.Join("", miwen1); 146 return miwen; 147 } 148 } 149 //维吉利亚 150 public string Virginia(int xuanze, string psd, string key) 151 { 152 string List = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 153 //先构建对应的秘钥 154 key = key.ToUpper(); 155 char[] key1 = new char[key.Length]; 156 int j = 0; 157 foreach (char e in key) 158 { 159 key1[j] = e; 160 j++; 161 } 162 j = 0; 163 ; string keywords = ""; 164 for (int i = 0; i < psd.Length; i++) 165 { 166 keywords += key1[j]; 167 j++; 168 if (j == key.Length) 169 { 170 j = 0; 171 } 172 } 173 psd = psd.ToUpper(); 174 string miwen = ""; 175 if (xuanze == 1) 176 { 177 int m = 0, n = 0, k = 0, s = 0; 178 foreach (char e in psd) 179 { 180 m = List.IndexOf(e); 181 n = List.IndexOf(keywords.Substring(k, 1)); 182 s = (m + n) % 26; 183 Console.Write(s); 184 miwen += List.Substring(s, 1); 185 k++; 186 } 187 return miwen; 188 } 189 else 190 { 191 int i = 0; 192 while (i < psd.Length) 193 { 194 int jj = i % key.Length; 195 int x1 = List.IndexOf(key.Substring(jj, 1)); 196 int x2 = List.IndexOf(psd.Substring(i, 1)); 197 if (x2 < x1) 198 { 199 x2 += 26; 200 miwen += List.Substring(x2 - x1, 1); 201 } 202 else 203 { 204 miwen += List.Substring(x2 - x1, 1); 205 } 206 i++; 207 } 208 return miwen; 209 } 210 } 211 //转换加密方法——密钥类型为int 212 public string ConvertingEncrypted(int xuanze, string psd, int key) 213 { 214 string npsd = ""; 215 foreach (char e in psd) 216 { 217 if (e != \' \') 218 { 219 npsd += e; 220 } 221 } 222 int total; 223 if (npsd.Length % key == 0) 224 { 225 total = npsd.Length / key; 226 } 227 else 228 { 229 total = npsd.Length / key + 1; 230 } 231 //实现解密或加密过程 232 string[] password1 = new string[total]; 233 Stack<char> stacks = new Stack<char>(); 234 int x = 0, y = 0; 235 foreach (char e in npsd) 236 { 237 stacks.Push(e); 238 y++; 239 if (y == key) 240 { 241 while (0 != stacks.Count) 242 { 243 password1[x] += stacks.Pop(); 244 } 245 y = 0; 246 x++; 247 } 248 } 249 while (0 != stacks.Count) 250 { 251 password1[x] += stacks.Pop(); 252 } 253 //形成密文或原文 254 string miwen = ""; 255 for (int i = 0; i < total; i++) 256 { 257 miwen += password1[i]; 258 } 259 return miwen; 260 } 261 //来一个重载的方法 262 public string ConvertingEncrypted(int xuanze, string psd, string key) 263 { 264 //去除原文/密文中的空格
265 string npsd = "";
266 foreach (char e in psd)
267 { 268 if (e != \' \') 269 { 270 npsd += e; 271 } 272 } 273 int total; 274 //做一个是否拆完的标记,之后会用到,否则会报超出索引 275 bool chujin = false; 276 if (npsd.Length % key.Length == 0) 277 { 278 total = npsd.Length / key.Length; 279 chujin = true; 280 } 281 else 282 { 283 total = npsd.Length / key.Length + 1; 284 chujin = false; 285 } 286 //按照密钥长度拆分原文 287 string[] password1 = new string[total]; 288 int x = 0, y = 0; 289 foreach (char e in npsd) 290 { 291 password1[x] += e; 292 y++; 293 if (y == key.Length) 294 { 295 y = 0; 296 x++; 297 } 298 } 299 //按照密钥字符串各个字符的顺序形成密文,有点晕,我觉得应该是这样的——这样要求密钥中不存在处重复的字符 300 string List = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 301 int[] shunxu = new int[key.Length];//记录密钥字母顺序数组(4321) 302 key = key.ToUpper();//将密钥全部转换成大写以便于一List进行比较 303 int i = 0;//声明一个标志值下面确定int数组的前进 304 foreach (char e in List) 305 { 306 if (key.IndexOf(e) >= 0) 307 { 308 shunxu[i] = key.IndexOf(e); 309 i++; 310 } 311 } 312 int[] nshunxu = new int[key.Length];//加密时,处理顺序使adbc的0231变成0312 313 for (int ni = 0; ni < key.Length; ni++) 314 { 315 for (int si = 0; si < key.Length; si++) 316 { 317 if (shunxu[si] == ni) 318 { 319 nshunxu[ni] = si; 320 break; 321 } 322 } 323 } 324 if (xuanze==1) //加密时,处理顺序使adbc的0231变成0312 325 { 326 shunxu = nshunxu; 327 } 328 if (!chujin)//如果没有除尽让最后一个数组剩余的字符为! 329 { 330 int length = key.Length - password1[total - 1].Length; 331 for (int xs = 0; xs < length; xs++) 332 { 333 password1[total - 1] += \'!\'; 334 } 335 if(xuanze==2)//如果是解密最后一个没有整数拆分的要还原成加密状态 336 { 337 int iiis = 0; 338 string mm = ""; 339 while (iiis < key.Length) 340 { 341 mm += password1[total-1].Substring(shunxu[iiis], 1); 342 iiis++; 343 } 344 password1[total - 1] = mm; 345 } 346 } 347 //加密解密操作核心,加密解密可以使用同一个算法 348 //将所有切分字符串按照密钥顺序排序 349 string[] password2 = new string[total]; 350 int ii = 0; 351 while (ii < key.Length) 352 { 353 for (int j = 0; j < total; j++) 354 { 355 password2[j] += password1[j].Substring(shunxu[ii], 1); 356 } 357 ii++; 358 } 359 //将最后一个未除尽数组中的!删除 360 if (!chujin) 361 { 362 string midpad = ""; 363 foreach (char e in password2[total - 1]) 364 { 365 if (e != \'!\') 366 { 367 midpad += e; 368 } 369 } 370 password2[total - 1] = midpad; 371 } 372 //将所=切分的字符串连接 373 string miwen = ""; 374 for (int s = 0; s < total; s++) 375 { 376 miwen += password2[s]; 377 } 378 return miwen;
379 }
380 }