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 }