【寫(xiě)在前面】這篇文章是我?guī)煾底罱难獊?lái)潮寫(xiě)的,主要介紹如何在無(wú)密鑰的情況下使用數(shù)學(xué)方法破解維吉尼亞密碼,一共分為三個(gè)部分,會(huì)預(yù)設(shè)讀者——也就是你——已經(jīng)了解了維吉尼亞密碼的基本操作方法,并具備一定的數(shù)學(xué)知識(shí)。當(dāng)然,如果你完全不了解這些,他在最后也附上了破解的操作性方法和部分C++代碼以供使用。不過(guò),如果你能聽(tīng)得懂前面的內(nèi)容,建議還是聽(tīng)一聽(tīng),這樣如果破解的時(shí)候出了問(wèn)題,自己就能排查。
第一部分:如何把維吉尼亞密碼寫(xiě)成誰(shuí)也看不懂的樣子
為了讓計(jì)算機(jī)也能處理維吉尼亞密碼的密文,我們要先定義這種加密方式。為了更通俗易懂地說(shuō)明,我們先從凱撒密碼開(kāi)始。
代換密碼的本質(zhì)是用另一個(gè)符號(hào)代替明文中的符號(hào),即明文所使用的符號(hào)集 和密文所使用的符號(hào)集 是一一對(duì)應(yīng)的雙射關(guān)系。用數(shù)學(xué)語(yǔ)言表示就是:對(duì)于映射 ,如果集合 中的任意兩個(gè)不同元素 ,都有 ,且對(duì)于集合 中的任一元素 ,都有集合 中的元素 使得 ,那么這個(gè)映射 就是雙射。
破解密碼的過(guò)程實(shí)質(zhì)上就是尋找這兩個(gè)集合之間的對(duì)應(yīng)關(guān)系,即求解逆映射 的過(guò)程。在凱撒密碼中,代換方式是使用26個(gè)字母相互替換,因此可以表示為英文字母集的自映射,即 。凱撒密碼的加密方式是:對(duì)于集合 中的某一個(gè)字母,都使用其后一個(gè)字母來(lái)替換(如果是字母z,那么使用字母a來(lái)替換)。因此,我們可以先將字母用數(shù)字代替,然后使用一個(gè)定義在模26剩余類(lèi)加群上的函數(shù)來(lái)表示凱撒密碼。具體定義過(guò)程如下:
首先,令a=0,b=1,c=2,以此類(lèi)推到z=25,,這樣一來(lái),凱撒密碼的加密方式就基本等同于“+1”,只有當(dāng)“25+1=26”后,才需要將26換成0。因此,我們可以用“取余”的方式來(lái)統(tǒng)一定義:“(25+1)mod 26=0”。
所以其次,定義一個(gè)剩余類(lèi)群 ,其代數(shù)運(yùn)算為模26剩余類(lèi)加法,即對(duì)于任意兩個(gè)元素 ,都有 。
這樣一來(lái),我們就能定義凱撒密碼的加密方式了:存在映射 ,使得任意的明文 都存在密文 滿足 ,其中映射 的具體形式為 。所以,反過(guò)來(lái)講,其解密方式為逆映射 。
當(dāng)然,繼凱撒密碼之后,我們還可以衍生出類(lèi)似的加密方式,比如每次不再用b替代a,而是用c替代a,即向后移動(dòng)兩位來(lái)加密,那么這時(shí)候的映射 就變?yōu)?a id="gallery_post_lCDDq" data-fancybox="gallery-post-1355992"> 。我們可以定義一個(gè)“密鑰”的概念來(lái)統(tǒng)合這些升級(jí)版本:設(shè)密鑰為自然數(shù) ,那么可以將凱撒密碼升級(jí)為 。
類(lèi)似地,代換密碼都可以用 的形式來(lái)定義,例如有名的仿射密碼,其密鑰為定義在 上的二元數(shù)組 ,加密方式為 ,解密方式為 。當(dāng)然,這不在我們今天的討論范圍之內(nèi)。
注意,上面的 、 都是代表單個(gè)字母,如果你要加密解密一整段文字,那么需要不斷重復(fù)這個(gè)過(guò)程。當(dāng)然,我們也可以直接用向量的方式來(lái)表示對(duì)一整段文字的凱撒加密:即定義n維列向量 ,令密鑰為n維列向量 ,其中 ,加密方式就能寫(xiě)成 。
準(zhǔn)備工作完成,我們可以定義維吉尼亞密碼了。
維吉尼亞密碼也是凱撒密碼的升級(jí)版,即使用一個(gè)密鑰令明文中的不同字母使用不同的凱撒移位來(lái)加密。例如,密鑰是LOVE——對(duì)應(yīng)的數(shù)學(xué)表示就是(11,14,21,4),明文是Do you like apples——對(duì)應(yīng)的數(shù)學(xué)表示就是(3,14,24,14,20,11,8,10,4,0,15,15,11,4,18)。對(duì)于第一個(gè)字母D,使用密鑰中的L來(lái)加密,即(3+11)mod 26=14,代換為O;對(duì)于第二個(gè)字母o,使用密鑰中的O來(lái)加密,即(14+14)mod 26=2,代換為c;以此類(lèi)推,直到第五個(gè)字母,再回頭使用密鑰中的L來(lái)加密,代換為f,以此循環(huán)往復(fù),直至寫(xiě)出密文Oc tsf zdop oktwsn。
根據(jù)上述例子,我們將密鑰拓展到和明文長(zhǎng)度對(duì)應(yīng)后(例如,將密鑰擴(kuò)寫(xiě)成LOVELOVELOVELOV,長(zhǎng)度和明文Do you like apples一致),就能定義維吉尼亞密碼:對(duì)于映射 ,存在密鑰 ,使得對(duì)于任意的明文 ,都存在密文 ,使得 。
完成了數(shù)學(xué)上的定義后,下一個(gè)問(wèn)題是,如何破解呢?
第二部分:惟密文攻擊法,又名坑爹上司連個(gè)密鑰都沒(méi)法給我搞到讓我怎么開(kāi)展工作
相信密碼圈的朋友乃至是一般的網(wǎng)推圈朋友都聽(tīng)說(shuō)過(guò)“字頻統(tǒng)計(jì)法”。對(duì)于一段有意義文本,每個(gè)字母出現(xiàn)的頻率是不一樣的。例如,在英文中,e的使用頻率最高,z、q、x等就很少使用,以及某些字母在詞尾常見(jiàn)/罕見(jiàn),某兩個(gè)或三個(gè)字母的組合非常常見(jiàn)(如on、the等),等等等等。1970年Dewey,G統(tǒng)計(jì)了約438023個(gè)字母得到了一份英文字母頻率表(下稱(chēng)“26字母頻率表”):| 字母 | 頻率 | 字母 | 頻率 | 字母 | 頻率 | | A | 0.0788 | J | 0.0010 | S | 0.0634 | | B | 0.0156 | K | 0.0060 | T | 0.0978 | | C | 0.0268 | L | 0.0394 | U | 0.0280 | | D | 0.0389 | M | 0.0244 | V | 0.0102 | | E | 0.1268 | N | 0.0706 | W | 0.0214 | | F | 0.0256 | O | 0.0776 | X | 0.0016 | | G | 0.0187 | P | 0.0186 | Y | 0.0202 | | H | 0.0573 | Q | 0.0009 | Z | 0.0006 | | I | 0.0707 | R | 0.0594 | | |
這些規(guī)律有助于我們?nèi)ゲ聹y(cè)單表加密的文本。例如,如果你看到一段文本中,經(jīng)常出現(xiàn)“wkh”這個(gè)組合,那么你就可以猜測(cè)這是移位3的凱撒加密,wkh=the;又或者,你統(tǒng)計(jì)了整段文本,發(fā)現(xiàn)a出現(xiàn)的頻率遠(yuǎn)高于其他字母,那么你可以大膽猜測(cè)a=e。假設(shè),驗(yàn)證,根據(jù)詞義和構(gòu)詞規(guī)則不斷發(fā)展,逐漸地解開(kāi)一段密文。這就是字頻統(tǒng)計(jì)法。
然而,字頻統(tǒng)計(jì)法的前提是,密文本身沒(méi)有破壞符號(hào)的分布規(guī)律。但對(duì)于維吉尼亞這種不同字母使用不同凱撒的加密方式,你就沒(méi)法單純從密文文本的統(tǒng)計(jì)數(shù)據(jù)來(lái)進(jìn)行推測(cè)了。因此,我們需要更高端的方法。
首先需要確定的是密鑰長(zhǎng)度:如果能知道密鑰長(zhǎng)度  ,那么就可以將整個(gè)文本拆分為  組(例如第1個(gè)、第  個(gè)、第  個(gè)等等為一組),每一組就等于是一種凱撒加密。因此,首先介紹的是“克思斯基測(cè)試”。
因?yàn)槊荑€是周期性循環(huán)的,而文本中又常常會(huì)有the、and、for這類(lèi)常見(jiàn)的詞組,因此,我們期望一段長(zhǎng)文本中,總會(huì)有那么幾次恰好是同樣的密鑰字母加密了同樣的詞組,得到了一樣的字母組合。反過(guò)來(lái)講,若密文中出現(xiàn)兩個(gè)相同的字母組,它們所對(duì)應(yīng)的明文字母組未必相同,但相同的可能性很大。因此,克思斯基測(cè)試就是,將密文中相同的字母組找出來(lái),并對(duì)其相同字母數(shù)綜合研究,找出它們的相同字母數(shù)的最大公因子,就有可能提取出有關(guān)密鑰字的長(zhǎng)度  的信息。
我們結(jié)合一個(gè)栗子來(lái)講解。下面是一段維吉尼亞加密的文本:
CHREEVOAHMAERATBIAXXWTNXBEEOPHBSBQMQEQERBWRVXUOAKXAOSXXWEAHBWGJMMQMNKGRFVGXWTRZXWIAKLXFPSKAUTEMNDCMGTSXMXBTUIADNGMGPSRELXNJELXVRVPRTULHDNQWTWDTYGBPHXTFALJHASVBFXNGLLCHRZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJTAMRVLCRREMNDGLXRRIMGNSNRWCHRQHAEYEVTAQEBBIPEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHPWQAIIWXNRMGWOIIFKEE
可以發(fā)現(xiàn),CHR這個(gè)字母組出現(xiàn)了足足五次,因此我們可以猜測(cè)這恰好是同樣的詞組被同樣的密鑰給加密了。因此,數(shù)出它們中間間隔的字母?jìng)€(gè)數(shù),求取最大公因數(shù),很可能就是密鑰的長(zhǎng)度。例如,這段文本中的五個(gè)CHR中的每個(gè)C之間間隔165、70、40、10個(gè)字母,最大公因數(shù)為5,因此猜測(cè)密鑰長(zhǎng)度  。
但是,克思斯基測(cè)試也有缺陷,至少它不能排除有其他詞組被其他密鑰加密成同樣的CHR的可能性。而且,如果找不到足夠多的重復(fù)字母組,那么克思斯基測(cè)試也等于無(wú)用。所以我們需要新的工具。
我們假設(shè)一門(mén)語(yǔ)言由  個(gè)字母構(gòu)成,每個(gè)字母發(fā)生的概率為  ,其中  ,那么用概率論的語(yǔ)言來(lái)講,就是將你寫(xiě)下一個(gè)字母視為一個(gè)事件,該事件的隨機(jī)變量  一共有  種取值  、  、……、  ,其分布律為  。如果是完全隨機(jī)的文本,那么所有  的值應(yīng)該是一樣的,都是  ;但前面提到,有意義的英文文本中每個(gè)字母出現(xiàn)的概率并不一致。
接下來(lái),我們定義一個(gè)名叫“重合指數(shù)”(Coincidence Index)的概念。
我們知道字母e在英文文本中出現(xiàn)的概率是12.68%,那么如果在一段長(zhǎng)文本中,隨機(jī)選取兩個(gè)字母,發(fā)現(xiàn)都是e的概率是多少呢?沒(méi)錯(cuò),是  。類(lèi)似地,對(duì)于任一概率為  的字母  ,隨機(jī)選取兩個(gè)字母后都是  的概率為  。因此,對(duì)于一段文本,隨機(jī)選擇其中兩個(gè)字母,它們相同的概率為  。我們將這個(gè)數(shù)據(jù)記為重合指數(shù)  。對(duì)于一段完全隨機(jī)的英文字母文本,  ,而一段有意義的英文文本的  。
重合指數(shù)  可以用來(lái)描述這段文本的分布律,你可以將其類(lèi)比為一種“特征值”。如果密文的重合指數(shù)非常接近0.065,那么說(shuō)明它使用了單表替換;如果兩段密文的重合指數(shù)相似,那么說(shuō)明它們使用了同一種代換加密方式。
當(dāng)然,在處理實(shí)際密文的時(shí)候,我們不可能知道在這種加密方式下每種字母出現(xiàn)的真實(shí)概率  ,所以往往會(huì)用其估計(jì)值  來(lái)替代,其中  為密文長(zhǎng)度,  為某個(gè)字母  出現(xiàn)的頻次。這個(gè)估計(jì)值是怎么得到的呢?這就要用到組合數(shù)學(xué)的知識(shí)了!從  個(gè)字母中選擇兩個(gè),共有  種方法,而兩個(gè)字母都是  的選法有  種,所以,滿足“兩個(gè)字母相同”的選法共有  種。因此,選到兩個(gè)字母相同的概率即為“能讓兩個(gè)字母相同的選法”比上“隨便選兩個(gè)字母的選法”,得到  。
好,我們把話題扯回來(lái)。那么,面對(duì)一段維吉尼亞密文,我們就可以嘗試將其進(jìn)行分組,然后計(jì)算不同組的重合指數(shù),如果各組的重合指數(shù)平均看下來(lái)很接近0.065,那就說(shuō)明這種分組方法是正確的。例如,我們將上面那段密文5份5份地切開(kāi),然后將每份的第一個(gè)字母組成一組,每份的第二個(gè)字母組成一組,以此類(lèi)推組成5組,計(jì)算其重合指數(shù):0.06298、0.0681004、0.0686124、0.0608144、0.0724484,平均約為0.06659,比其他分組方法得到的數(shù)據(jù)更接近0.065,說(shuō)明密鑰長(zhǎng)度更有可能是5。
解決了密鑰長(zhǎng)度  的問(wèn)題后,我們將密文分為  組,每組內(nèi)都使用一種單一的凱撒加密:
第一組:CVABWEBQBUAWWQRWWXANTBDPXXRDWBFAXCWMNJJFAIACNRNCATBWKDMCDCQQXWK
第二組:HOEITESEWOOEGMFTIFUDSTNSNVTNDPASNHESBGSEGEMRDRSHEAIEORTHNHOANOE
第三組:RARANOBQRASAJNVRAPTCXUGRJRUQTHLVGRLJHNGYNQRRGINRYQPVEEBRVRHIRIE
第四組:EHAXXPQEVKXHMKGZKSEMMIMEEVLWYXJBLZEIWMLPRJVELMRQEEEKWMHTRCPIMI
第五組:EMTXBHMRXXXBMGXXLKMGXAGLLPHTGTHFLBKKRGXHBTLMXGWHVBEAAXHKZLWWGF
考慮到每組對(duì)應(yīng)的明文的可能性只有26種,所以我們需要暴力的范圍一下子從  (  為密文全長(zhǎng))降低到了  。可喜可賀,可喜可賀……個(gè)屁嘞!
此時(shí)字頻統(tǒng)計(jì)依舊不能用——因?yàn)槊拷M內(nèi)的密文都是間隔  個(gè)字母取到的,根本沒(méi)法猜測(cè)詞組、詞尾字母頻數(shù)等,而文本量的驟然減少也讓對(duì)單個(gè)字母的字頻統(tǒng)計(jì)變得不夠準(zhǔn)確(說(shuō)不定這組密文對(duì)應(yīng)的明文中,a出現(xiàn)的次數(shù)反而比e多呢?),導(dǎo)致原本在大文本的情況下使用的“邊猜邊湊”的方法已經(jīng)不能用了。如果是暴力破解,那等于是每組都要把26種位移可能性都試一遍,試個(gè)  組,這依舊不是人類(lèi)能完成的工程。
那么有什么思路可以使用嗎?既然單個(gè)字頻不靠譜,那我們可不可以整體性地將密文字母的分布律和“26字母頻率表”的分布律相比較?雖然可能在單個(gè)字母的概率上會(huì)有些許出入,但只要整體的那張“圖景”足夠相似不就好了?
你或許會(huì)問(wèn),對(duì)于每一組密文,我們都有26種位移可能,即便有時(shí)間將它們和26字母頻率表一一比較,我們又該憑什么斷言某一種位移可能比另一種要更“像”26字母頻率表呢?
還記得前面提到的重合指數(shù)法嗎?只不過(guò),前面是在同一段文本中隨機(jī)選取兩個(gè)字母,這次是在兩段文本中各隨機(jī)選取一個(gè)字母,這樣計(jì)算出來(lái)的“擬重合指數(shù)”就是  ,其中  就是密文的某一種位移后得到的字母的頻率,  就是字母的一般概率,也就是上面的26字母頻率表。這個(gè)“擬重合指數(shù)”越大,說(shuō)明兩段文本的字母的分布律越相像。而且據(jù)我的經(jīng)驗(yàn)來(lái)看,一般最大的那個(gè)指數(shù)也接近0.065。
因此,破譯的“擬重合指數(shù)法”就分為五個(gè)步驟:
第一步,統(tǒng)計(jì)每組密文中每個(gè)字母的頻數(shù)  、  、……、  。
第二步,計(jì)算每組密文的長(zhǎng)度  ,計(jì)算26個(gè)字母在該組中的頻率分布  、  、……、  。
第三步,找到一般文本的字母概率分布(即上面的頻率表)  、  、……、  。
第四步,對(duì)于頻率分布  進(jìn)行移位,得到26種排序。如果我草稿沒(méi)打錯(cuò),當(dāng)位移量為  的時(shí)候,原本的排序  、  、……、  就會(huì)變?yōu)?a id="gallery_post_vwW6B" data-fancybox="gallery-post-1355992">  、  、……、  、  、  、……、  ,可將這種排序設(shè)為26維向量  ,將第三步中的一般頻率的排序設(shè)為向量  。
第五步,計(jì)算26個(gè)相關(guān)值  ,其中最大的值所對(duì)應(yīng)的  即為該組密文的位移量。
只要按照這五步驟,將每組的位移量都找到,就可以拼湊出密鑰,獲得明文。
還是拿前面的例子,對(duì)于第一組字母,首先獲得  ,自然也就能得到其他25種排序。接著計(jì)算相關(guān)值,得到下表: | k | 0 | 1 | 2 | 3 | 4 | 5 | | CI | 0.0347667 | 0.0310079 | 0.0356968 | 0.0382286 | 0.0358683 | 0.0389302 | | k | 6 | 7 | 8 | 9 | 10 | 11 | | CI | 0.0273635 | 0.0281905 | 0.0490778 | 0.0616127 | 0.0390984 | 0.0316079 | | k | 12 | 13 | 14 | 15 | 16 | 17 | | CI | 0.0397143 | 0.0381111 | 0.0380333 | 0.0448175 | 0.0354571 | 0.0300444 | | k | 18 | 19 | 20 | 21 | 22 | 23 | | CI | 0.0421222 | 0.0422667 | 0.035781 | 0.0332317 | 0.0486841 | 0.043381 | | k | 24 | 25 | | | | | | CI | 0.0415127 | 0.0356937 | | | | |
可以發(fā)現(xiàn),除了  時(shí)相關(guān)值約為0.06,其他時(shí)候相關(guān)值都在0.03或0.04左右徘徊。因此可以確定,第一組的位移量為9,即密鑰的首位是J。
以此類(lèi)推,我們可以得到密鑰的五位分別是9、0、13、4、19,即JANET。而明文為:
THE ALMOND TREE WAS IN TENTATIVE BLOSSOM. THE DAYS WERE LONGER OFTEN ENDING WITH MAGNIFICENT EVENINGS OF CORRUGATED PINK SKIES. THE HUNTING SEASON WAS OVER, WITH HOUNDS AND GUNS PUT AWAY FOR SIX MONTHS. THE VINEYARDS WERE BUSY AGAIN AS THE WELL-ORGANIZED FARMERS TREATED THEIR VINES AND THE MORE LACKADAISICAL NEIGHBORS HURRIED TO DO THE PRUNING THEY SHOULD HAVE DONE IN NOVEMBER.
第三部分:保姆式操作說(shuō)明與部分C++代碼
要在沒(méi)有密鑰的情況下破解維吉尼亞密碼的步驟:
第一步:使用克思斯基測(cè)試或重合指數(shù)法,確定密鑰長(zhǎng)度;
第二步:根據(jù)密鑰長(zhǎng)度對(duì)密文進(jìn)行分組;
第三步:對(duì)每組密文使用擬重合指數(shù)法,確定位移量;
第四步:寫(xiě)出明文。
以下是我寫(xiě)的C++代碼,可自行取用。當(dāng)然,如果你聽(tīng)懂了前面兩部分,那你自己也能寫(xiě)。另外,如果密文長(zhǎng)度太短,則也不適合用這個(gè)方法,因?yàn)榻y(tǒng)計(jì)得到的字母頻率和正常的概率偏差過(guò)大,導(dǎo)致相關(guān)系數(shù)不夠準(zhǔn)確,此時(shí)建議大家直接暴力。
#include<iostream>#include<cstring> usingnamespace std; intmain() { //這是我看到的另一種字母概率表,你可以用它替換下一行使用:const float q[26] = {8.17,1.49,2.78,4.25,12.70,2.23,2.02,6.09,6.97,0.15,0.77,4.03,2.41,6.75,7.51,1.93,0.10,5.99,6.33,9.06,2.76,0.98,2.36,0.15,1.97,0.07}; const float q[26] ={7.88,1.56,2.68,3.89,12.68,2.56,1.87,5.73,7.07,0.10,0.60,3.94,2.44,7.06,7.76,1.86,0.09,5.94,6.34,9.78,2.80,1.02,2.14,0.16,2.02,0.06};//英文字母的概率 char t[500];//用于存儲(chǔ)密文 int s; int ss; cout << "密文是大寫(xiě)字母請(qǐng)輸入1,是小寫(xiě)請(qǐng)輸入0:"; cin >> ss; if (ss==1) { s = 65; } else { s = 97; }//區(qū)分大小寫(xiě) cout << "請(qǐng)輸入密文:"; cin >> t;//輸入密文 const int long_of_text = strlen(t);//確定密文長(zhǎng)度 int m_min; int m_max; int m;//實(shí)際的密鑰長(zhǎng)度,之后有用 cout << "請(qǐng)輸入密鑰長(zhǎng)度范圍(最小值):"; cin >> m_min; cout << "請(qǐng)輸入密鑰長(zhǎng)度范圍(最大值):"; cin >> m_max; for (int fenzu=m_min; fenzu<=m_max;fenzu++) { int number_of_zu = long_of_text /fenzu; int shen_yu = long_of_text % fenzu; if (shen_yu != 0) { number_of_zu++; } else { shen_yu = fenzu; }//完成分組 int mi_wen[number_of_zu][fenzu]; int fenchai = 0; for (int row=0; row<number_of_zu;row++) { for (int col=0; col<fenzu;col++) { if (fenchai<long_of_text)//fenchai的編號(hào)是從0開(kāi)始,所以不能用小于等于 { mi_wen[row][col] =t[fenchai] - s;//因?yàn)榇髮?xiě)字母A的數(shù)字是65 } fenchai++; } }//將密文轉(zhuǎn)化為數(shù)字,存進(jìn)二維數(shù)組中 float CI_guji = 0.0; for (int col=0; col<fenzu; col++) { int chang_du_L = number_of_zu; if (col>=shen_yu) { chang_du_L--; }//得到該組實(shí)際的密文長(zhǎng)度 int f[26] = {0};//用于計(jì)算字頻 for (int row=0; row<chang_du_L;row++) { f[mi_wen[row][col]]++; }//計(jì)算每個(gè)字母的頻數(shù) for (int i=0; i<26; i++) { CI_guji = CI_guji +1.0*f[i]*(f[i]-1)/chang_du_L/(chang_du_L-1); } }//針對(duì)每一組,進(jìn)行重合指數(shù)分析 CI_guji = CI_guji / fenzu; cout << "m=" <<fenzu << ":" << CI_guji << endl; } cout << "請(qǐng)輸入最接近0.065的m:"; cin >> m;//輸入密鑰長(zhǎng)度 cout << "密鑰為:"; //不要問(wèn)我為什么不把下面這段和上面一模一樣的內(nèi)容做成函數(shù),因?yàn)槲也恢涝趺捶祷財(cái)?shù)組。咱只是一個(gè)數(shù)學(xué)系的半吊子,其實(shí)根本不懂寫(xiě)代碼 int number_of_zu = long_of_text / m; int shen_yu = long_of_text % m; if (shen_yu != 0) { number_of_zu++; } else { shen_yu = m; } int mi_wen[number_of_zu][m];//存儲(chǔ)密文的二維數(shù)組 int ming_wen[number_of_zu][m];//將用于存儲(chǔ)明文的二維數(shù)組 int fenchai = 0; for (int row=0; row<number_of_zu; row++) { for (int col=0; col<m; col++) { if (fenchai<long_of_text) { mi_wen[row][col] = t[fenchai] - s; } fenchai++; } } for (int col=0; col<m; col++) { int chang_du_L = number_of_zu; if (col>=shen_yu) { chang_du_L--; } int f[26] = {0};//字母頻數(shù) float p[26] = {0.0};//字母頻率 for (int row=0; row<chang_du_L;row++) { f[mi_wen[row][col]]++; } for (int i=0; i<26; i++) { p[i] = 1.0 * f[i] / chang_du_L; }//計(jì)算每個(gè)字母的頻率 double corr = 0.0;//相關(guān)值卷積 double corr_max = 0.0;//最大相關(guān)值 int max_number = 0;//最大對(duì)應(yīng)的位移數(shù) float pp[26] = {0.0};//用于移動(dòng)26個(gè)字母頻率的不同序列 for (int k=0; k<26; k++) { for (int i=0; i<26; i++) { pp[i] = p[(k+i)%26]; } for (int j=0; j<26; j++) { corr = corr + pp[j] *(q[j]/100); } if (corr > corr_max) { corr_max = corr; max_number = k; } corr = 0; } for (int i=0; i<chang_du_L; i++) { ming_wen[i][col] = (mi_wen[i][col]+ 26 - max_number) % 26; } char key = max_number + s; cout << key; } for (int row=0; row<number_of_zu; row++) { for (int col=0; col<m; col++) { t[row*m+col] = ming_wen[row][col] +s; } } cout << endl << "明文為:"<< t; //實(shí)際輸出的明文末尾可能會(huì)帶有幾個(gè)亂碼,但不影響前面的內(nèi)容 return 0; }
下面是本文的例子的輸出結(jié)果:
密文是大寫(xiě)字母請(qǐng)輸入1,是小寫(xiě)請(qǐng)輸入0:1
請(qǐng)輸入密文:CHREEVOAHMAERATBIAXXWTNXBEEOPHBSBQMQEQERBWRVXUOAKXAOSXXWEAHBWGJMMQMNKGRFVGXWTRZXWIAKLXFPSKAUTEMNDCMGTSXMXBTUIADNGMGPSRELXNJELXVRVPRTULHDNQWTWDTYGBPHXTFALJHASVBFXNGLLCHRZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJTAMRVLCRREMNDGLXRRIMGNSNRWCHRQHAEYEVTAQEBBIPEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHPWQAIIWXNRMGWOIIFKEE
請(qǐng)輸入密鑰長(zhǎng)度范圍(最小值):1
請(qǐng)輸入密鑰長(zhǎng)度范圍(最大值):9
m=1:0.0450152
m=2:0.0432958
m=3:0.0466458
m=4:0.0416841
m=5:0.0665911
m=6:0.0438283
m=7:0.0424544
m=8:0.0420378
m=9:0.0455366
請(qǐng)輸入最接近0.065的m:5
密鑰為:JANET
明文為:THEALMONDTREEWASINTENTATIVEBLOSSOMTHEDAYSWERELONGEROFTENENDINGWITHMAGNIFICENTEVENINGSOFCORRUGATEDPINKSKIESTHEHUNTINGSEASONWASOVERWITHHOUNDSANDGUNSPUTAWAYFORSIXMONTHSTHEVINEYARDSWEREBUSYAGAINASTHEWELLORGANIZEDFARMERSTREATEDTHEIRVINESANDTHEMORELACKADAISICALNEIGHBORSHURRIEDTODOTHEPRUNINGTHEYSHOULDHAVEDONEINNOVEMBER礱
Process returned 0 (0x0) execution time : 19.595 s
Press any key to continue. |