過了個年回來有點時間,就將上個學期的Cybersecurity的期末實驗寫上來給大家提供點思路吧~,當時讓小白B半天摸不着頭緒的一道破譯簡單加密的題目. 放上參考代碼鏈接 https://github.com/toufuChew/monoalphabeticCipher
問題如下:
分析破解一個基於簡單代替密碼(simple substitution cipher)加密的密文,不考慮標點符號。
這個問題理解起來很簡單,它說的簡單替代密碼,顧名思義,加密過程就是將明文的一個字符用相應的一個密文字符代替。而單字母密碼分兩種不同的加密形式,一個單表代換密碼,一個多表代換。
這裏要破譯的密文就是單表的替換加密的密文,加密時密鑰空間K是26英文字母之間的排列組合,每個明文字母與另一密文字母唯一對應,K集合元素就有26!。例如
明文: my lazy dog is living comfortably in SZU
密文: ow npbw gdm ar nasafm qdoudkcpgnw af rbv
明文加密成密文都是在一張簡單的映射表的基礎上一一替換進行的。這種映射表可以由多種方式生成,下面簡單介紹其中一種,我們的重點是在破譯部分。
加密方式:
代替法-
採用另一個亂序字母表來替代明文字母,明文字母和密文字母保持一一對應關係。要得到一個亂序字母表,可以採取隨機排列的方式,也可以由一張混淆字母表生成,過程如下:
步驟
a) 隨機選擇一個密鑰字或密鑰短語,例如:cybersecurity
b) 去掉重複字母:cybersuit
c) 這些字母構成矩陣的第一行,矩陣的後續各行由標準字母表中去掉密鑰字的字母后剩下的字母構成(下圖)
d) 按列取出矩陣中的字母得到混淆字母表:canydobfpegqrhvsjwukxilztm
private char[] createCodingTable(){
Random random = new Random();
String keychar = "";
int keyWordLength = random.nextInt(5) + 5 ; // 5 - 9
char [][]matrix = new char[(int) Math.ceil(26. / keyWordLength)][keyWordLength];
for (int i = 0; i < matrix.length; i++)
for (int j = 0; j < keyWordLength; j++)
matrix[i][j] = 0;
while(keyWordLength -- > 0){
int key = random.nextInt(26) + 'a';
while(keychar.contains((char)key + "")) key = random.nextInt(26) + 'a';
keychar += (char)key;
matrix[0][keyWordLength] = (char)key;
}
keyWordLength = matrix[0].length;
for (char i = 'a', t = 0; i <= 'z'; i++)
if (!keychar.contains(i + ""))
matrix[(i - 'a' - t) / keyWordLength + 1][(i - 'a' - t) % keyWordLength] = i;
else t++;
char []codingTable = new char[26];
for (int i = 0, t = 0; i < keyWordLength; i++)
for (int j = 0; j < matrix.length; j++){
if (matrix[j][i] != 0x0)
codingTable[t ++] = matrix[j][i];
}
return codingTable;
}
**密碼破譯部分**
我們知道靠暴力窮舉去驗證破譯的正確性是不可行的,這樣最糟糕的嘗試的次數爲26!,時間複雜度過高。
字母頻率分析
對於單字母替換,最常用的方法就是統計字母頻率,圖1。
由於明文字母與密文字母是一一對應的關係,所以替換前後的字母出現頻率是相同的,我們就可以根據替換後的字母頻率與已知的字母頻率相對應,就可以分析出替換前的字母。
圖 1
字母頻率是依賴於單詞的構造形式的,這些值在規模較大的英文文本中是趨於穩定的,所以對不同的文本作字母統計的結果都會十分接近於圖1.1的分佈,其中字母e的頻率遠高於其他字母。這時候即便它被字母替換成密文,我們只要統計其中的字母頻率,根據頻率的高低就可以大致推測得出它可能是哪個明文字母。
侷限性:
短文本的時候由於詞彙出現的種類和數量有限,這使得我們統計出來的字母頻率沒有明顯的區分度。當字母頻率分佈越均勻,得到的映射密鑰k就越不確定,正確率也就越低。即使成功解密了前面的幾個字母,但對於整篇的密文來說僅靠幾個字母是很難猜測出原本的意思的,這是因爲密鑰空間太大的關係,我們需要想辦法在短文本的情況下依然能夠有效的縮減破解的密鑰空間K。
如果我們找到一個可以分析小文本密文的方法,那麼對於大文本來說就不是問題,只要截取大文本的一部分進行分析就可以了。
單詞分析法
借鑑單字母的頻率分析,我們可以考慮分析單詞的頻率。這是因爲
1. 密文仍保留了明文的單詞特徵,包括長度和頻率。
2. 單詞的頻率特徵在短文本比字母更加明顯。
3. 一元詞與二元詞數量是很有限的,最常見的有
一元詞6個S= {a, i, s, t, m, d};
二元詞25個D= {of, to , in, …};
部分三元詞T;
正常的文本必然有一元詞或二元詞出現在上面的表中,這比如I’d …裏的I和d。英語句子裏的謂語is, 介詞of,關係代詞he等都是不可少的,我們就利用這個因素將密文中長度爲1或2的詞解空間固定在這31個詞裏。
其餘單詞特徵分析
元音字母
一個單詞除個別語氣詞外都由5個元音字母組合成,對於只剩一個未破解字母的單詞且都沒有元音字母的情況,密文空間爲{a,e,i,o,u}。
雙字母
有一類單詞可以進一步幫我們縮小密鑰空間,像是 look 這樣含有doubleletters的詞,參考資料說明這樣的字母不包括字母j, v, w, x, y (savvy ,www特殊處理).這樣我們遇到雙字母單詞可以排除上面5個明文字母的可能。
單詞類
package com.cryptanalysis;
/**
* FormalWords provide reference from formal construction of words
* @author cq
*
*/
public class FormalWords {
public static String formalSingle[] = {"a", "i", "s", "t", "m", "d"};
public static String formalDouble[] = {"of", "to", "in", "it", "is", "be", "as",
"at", "so", "we", "he", "by", "or", "on", "do", "if", "me", "my", "up", "an", "go", "no", "us", "am", "ll"};
public static String formalTriple[] = {"the", "and", "for", "are", "but", "not",
"you", "all", "any", "can", "had", "her", "was", "one", "our", "out",
"day", "get", "has", "him", "his", "how", "man", "new", "now", "old",
"see", "two", "way", "who", "boy", "did", "its", "let", "put", "say", "she", "too", "use", "etc"};
public static String coupleLetter[] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "z", "q"};
public static String vowel = "aeiou";
public static String alphabet = "abcdefghijklmnopqrstuvwxyz";
}
算法實現思路請看我下一篇博客:
單字母密碼密碼分析(下) 點擊打開鏈接