Vigenere加密法原理很簡單,實現起來也不難。與普通的單碼加密法不同,明文經過加密之后,每個字母出現的頻率就不會有高峰和低峰。
密鑰中字母代表行和明文中的字母代表行。在vigenere表中找到對應的字母即可。當明文的長度大於密鑰的長度的時候,密鑰重復使用。下面是go語言的實現版本。
vigenege表
var arr [27][27]int //Vigenere表 var key string = "hold" //密鑰 //初始化vigenere表 func init() { arr[0][0] = 0 for i := 0; i < 2; i++ { for j := 1; j < 27; j++ { arr[i][j] = 'a' + j - 1 } } for i := 1; i < 27; i++ { arr[i][0] = 'a' + i - 1 } var num int = 0 for i := 26; i > 0; i-- { for j := 2; j < 27; j++ { arr[j][i] = 'a' + num num++ if num%26 == 0 { num = 0 } } } }
//進行加密 func encrypt(str string) []byte { count := 0 var ciphertext []byte = []byte(str) length := len(key) for i := 0; i < len(str); i++ { ciphertext[i] = byte(arr[str[i]-'a'+1][key[count]-'a'+1]) count++ count %= length } return ciphertext }
在很長的一段時間內Vigenere加密法一直被認為是無法破解的。我們可以通過IC(index of coincidence)值來得到密鑰的長度。這里還要用到MR(measure of roughness)。當所有字母都均勻分布,那么選取每個字母的概率都相同。為1/26。那么從一段密文中選取某個字母的概率與均勻分布的概率偏差為
MR就是a-z中所有的字母的偏差的和。
展開后在進行一些簡單的計算可以得到
在MR中唯一依賴密文的地方就是。其值為密文中 i 單詞出現的次數與密文長度的比值。那么
和IC為
知道了IC值之后,我們可以用IC值,當IC值在0.038與0.066之間時。則表示采用了多碼加密法。但我們任然無法准確的得到密鑰的長度。1863年Kasiski提出了破解Vigenere的方法。當我們利用密鑰加密的時候,總是重復的利用密鑰進行加密,當加密后的密文中有重復的字符串則是密鑰中相同的部分加密后得到的。當然,也有可能是偶然情況導致的,不過偶然情況不可能出現長串的相同字符串。因此偶然情況的影響可以消除。如下,第一段的 RUN 為密鑰,中間是明文,最后為加密后的密文。
R U N R U N R U N R U N R U N R U N R U N R U N R U N
t o b e o r n o r t o b e t h a t i s t h e q u e s t
K L O V I E E I G K I O V N U R N V J N U V K H V M G
可以觀察到密文中'KLOV'出現了兩次,‘NU’同樣也出現了兩次。而重復出現的密文則表示了密鑰使用的次數。因此,上述的密鑰長度應為6和9的公約數。當獲得足夠多的密文之后,就可以得到密鑰的長度。
有了密鑰的長度就意味着我們可以把密文分為密鑰長度個集合,且這些集合是由同個字母單碼加密得到的。比如上述密文,我們得到密鑰長度為3,對於密文,我們每3個一循環,那么我們可以得到3個集合
K V E K V R J V V 由R加密的集合
L I I I N N N K M 由U加密的集合
O E G O U V U H G 由N加密的集合
接下來我們可以分別破解3個由單碼加密的密文,Vigenere則宣告被破解。