要了解单表替代密码就得先了解替代密码,在这里我就做一下简单的介绍:
替代是古典密码中用到的最基本的处理技巧之一 。
替代密码是指先建立一个替换表,加密时将需要加密的明文依次通过查表,替换为相应的字符,明文字符被逐个替换后,生成无任何意义的字符串,即密文,替代密码的密钥就是其替换表。
根据密码算法加解密时使用替换表多少的不同,替代密码又可分为单表替代密码和多表替代密码。
单表替代密码的密码算法加解密时使用一个固定的替换表。单表替代密码又可分为一般单表替代密码、移位密码、仿射密码、密钥短语密码。
这里讲单表替代密码的直接攻击。
对于自然语言,如果取一本非专业书籍,统计足够长的课文就会发现,字母(或字符)出现的频率会反映出相应语言的统计特性。统计大量的课文定会发现,相应语言中每个字母在相应语言中出现的概率。于是便得到该语言字母表上的一个概率分布。
一、英文字母
一由独立试验产生明文单码,Beker在1982年统计的样本总数为100 362,得到单码的概率分布见下表:
根据上表,英文字母出现的概率按大小排列如下:
E T A O I N S H R D L C U M W F G Y P B V K J X Q Z
在上表中,不少字母出现的概率近乎相等。为了应用方便,常将英文字母表按字母出现的概率大小分类,分类情况见下表:
--------------------------
极高频 E
次高频 T A O I N S H R
中等频 D L
低频 C U M W F G Y P B
甚低频 V K J X Q Z
--------------------------
其它语言和数据也有类似于英语语言的单字母统计特性。如果我们随意统计一段足够长的英文课文,只要内容不是太特殊,其结果一定和上表基本相同。这表明英文的一篇文章中各个字母出现的概率是基本可预测的,它将为密码分析提供一个方面的依据。
语言的单字母统计特性至少在以下两个方面没有反映出英文语言的特征:
⑴根据英文的单字母统计特性可以计算出双字母QE出现的概率为p(QE)=0.00095×0.12702≈1.21×10^(-4)
这就是说,在10^6个双字母的抽样中,QE出现的次数大约应为121次,但这不符合英文课文的实际。因为在英文课文中,QE根本不出现。
⑵四字母SEND和SEDN在单字母统计特性下出现的概率相等,这也不符合英文的实际。总之,自然语言的单字母统计特性只反映了单字母出现的概率,而没有反映该种语言文字的字母间的相关关系。为了体现自然语言的双字母统计特性,我们需要考察该语言的文字中相邻字母对出现的频数。
二、由独立试验产生双字母。根据Beker在1982年统计的英文双字母的频数给出了双字母的频率。
统计出的英文双字母的概率最大的30对字母按概率大小排列为:
th
he in er an re ed on es st en at to
nt ha nd ou ea ng as or ti is et it
ar te se hi of
只要我们随意统计足够长的英文课文,只要内容不是太特殊,其结果一定和上面的概率基本相同,这也表明双字母在英文课文中出现的概率是基本可预测的,它为密码分析提供了又一方面的依据。
类似的,我们还可以考察英文课文中三字母出现的频率。仍按Beker在1982年统计的结果(样本总数100 360)得到概率最大的20组三字母按概率大小排列为:
the
ing and her ere ent tha nth was eth for
dth hat she ion his sth ers ver
特别,the出现的频率几乎为ing的3倍。
应当强调指出,在利用统计分析法时,密文量要足够大,否则会加大密码攻击的难度。在实际通信中,除了字母外,还有诸如标点、数字等字符,它们的统计特性也必须考虑进去。数据格式、报头信息对于密码体制的安全有重要意义,在密码分析中也起着重要的作用。
在分析或攻击一份密报时利用英文的下述统计特性很有帮助。
⑴冠词the对英文的统计特性影响很大,它使t,h,th,he和the在单字母、双字母和三字母的统计中都为高概率的元素。
⑵英文单词中以 E,S,D,T 为结尾的超过一半
⑶英文单词中以 T,A,S,W 为起始字母的约占一半
⑷①在分析或攻击密文时应先找突破口,一般来说,先从the a i入手。(能一个字母独立作为单词的只有a、I,而且频率较高时优先考虑a)
②如果有“’”出现,“’”后的一个字母只能是t s l d v中的一个;如果是两个字母,则只能是re ll。(两个不同字母即是re,相同即是ll)
③其它规律:如果四字单词词末有两个相同字母,往往是ll;
以a开头的三字单词只能是and are中的一个;
两个字母的组合中如果出现q*,则*是u(q后几乎总是u);
如果一个单词的开头和结尾是同一个字母,最可能的是:s t d;
两个都是辅音的双字母组合,常含有n或t;io、ou和ea是最常见的双元音字母组;
如果单词的头两个字母都是辅音,则第二个字母最可能是:r、l和h;
如果一个三次以三个辅音结尾,那最常见的是-ght和-tch;
反向双字母组合: er-re, es-se, an-na, it-ti, on-no, en-ne, ot-to,ed-de, st-ts, at-ta, ar-ra, in-ni;
小词的使用频率
1-letter: a,i,o
2-letter: of,to,in,is,it,be,as,at
3-letter: the,and,for,are,but,not,you,all
4-letter: that,with,have,this,will,your,from,they
5-letter: which,would,there
元音字母:a,e,i,o,u
元音后最常见的字母是n,元音前最常见的字母是h
常见的双字母前缀 re co un com il ir up
最常用的三字母后缀 ion ing
最常见词尾 ed es er
【例】
1.攻击例题:
给定密文为GROX CMRYYVLYIC COXN COMBOD WOCCKQOC
DY OKMR YDROB DROI YPDOX SXFOXD K MYNO LI VODDSXQ OKMR VODDOB YP DRO
KVZRKLOB BOZBOCOXD KXYDROB YXO
攻击的第一步是做出密文字母出现的频次分布表
第二步是根据密文字母的频次统计,确定某些密文字母对应的明文字母可能是单字母频率统计表中的哪些字母。此例中
密文字母 对应的明文字母
O,D,B,V e,t,r,l
第三步是利用自然语言的文字结合规律进行猜测。D经常出现在词头或词尾,故猜测它与t对应;而P经常在词尾出现而未在词头出现,所以猜测它与明文字母e对应;K单独出现且频率较高,猜测与a对应。
利用双字母、三字母统计特性及元音辅音拼写知识,可猜测如下:
由此不难猜出:GROX是when,OKMR是each,VODDSXQ是letting,KXYDROB是another,DY是to。
再得到下表:
再做进一步确定就可确定C,W,I,N,F,Q,Z对应的明文字母。经过整理恢复的明文如下:
when
schoolboys send secret messages to each other they often invent a code
by letting each letter of the alphaber represent another one.
算法实现
1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 using namespace std; 5 const char c[27]={‘d‘,‘j‘,‘k‘,‘z‘,‘u‘, 6 ‘x‘,‘c‘,‘m‘,‘l‘,‘i‘,‘w‘,‘b‘,‘v‘,‘n‘,‘o‘,‘p‘, 7 ‘q‘,‘a‘,‘r‘,‘s‘,‘g‘,‘h‘, 8 ‘f‘,‘t‘,‘y‘,‘e‘,‘ ‘}; 9 void encryption(ifstream& fin,ofstream& fout); 10 int main() 11 { 12 ifstream fin; 13 ofstream fout; 14 fin.open("file1_1.in"); 15 if(fin.fail()) 16 { 17 cout<<"File open error!(Input)"<<endl; 18 exit(1); 19 } 20 fout.open("file1_1.out"); 21 if(fout.fail()) 22 { 23 cout<<"File open error!(Output)"<<endl; 24 } 25 encryption(fin,fout); 26 fin.close(); 27 fout.close(); 28 return 0; 29 } 30 void encryption(ifstream& fin,ofstream& fout)//加密过程 31 { 32 char next; 33 char ch; 34 int i; 35 while(fin.get(next)) 36 { 37 if(next>=‘a‘&&next<=‘z‘) 38 { 39 i=next-‘a‘; 40 ch=c[i]; 41 fout<<ch; 42 } 43 else 44 { 45 fout<<‘ ‘; 46 } 47 } 48 } 49 void decryption(ifstream& fin,ofstream& fout)//解密过程 50 { 51 char ch; 52 char chout; 53 while(fin.get(ch)) 54 { 55 for(int i=0;i<=26;i++) 56 { 57 if(ch==c[i]) 58 { 59 if(i==26) 60 { 61 fout<<‘ ‘; 62 } 63 else 64 { 65 chout=char(‘a‘+i); 66 fout<<chout; 67 } 68 } 69 } 70 } 71 }
输入文件file1_1.in
//file1_1.in we will attack tomorrow morning
输出文件file1_1.out
//file1_1.out fu flbb dssdkw sovoaaof voanlnc