首先來看以下愷撒密碼。
離散數學的一道作業題。
凱撒密碼作為一種最為古老的對稱式加密體制,在古羅馬的時候都已經很流行,他的基本思想是:通過把字母移動一定的位元來實現加密和解密。例如,如果密匙是把明文字母的位元向後移動三位,那麼明文字母B就變成了密文的E,依次類推,X將變成A,Y變成B,Z變成C,由此可見,位元就是凱撒密碼加密和解密的密鑰。
題目如下:
It is known that the following crypted paragraph is encryted using a slighted enhanced Caesar encryption method of the form f(p)=(ap+b)mod29.
jgc!.chr, dhdw,nbn bn kdncy oh uxc jdru uxdul bh dh, qbfch nugcurx oj mgbuuch wdhq.dqcl rcgudbh wcuucgn dhy roakbhdubohn oj wcuucgn orr.g mbuxfdg,bhq jgc!.chrbcns aogcofcgl uxcgc bn d rxdgdrubnubr ybnugbk.uboh oj wcuucgn uxdu bn go.qxw, uxc ndac jog dwaonu
dww ndavwcn oj uxdu wdhq.dqcs
What is also known is the two most frequently used letters in the paragraph are t and e.The reference alphabet is an array of length 29 "abcdefghijklmnopqrstuvwxyz,.!", indicating that space is not handled during encryption (space remains space). Try to de-cypher
the message and give the plaintext.
簡單理解就是解密一段文字,加密方式為f(p)=(ap+b)mod29的凱撒加密方式,算是愷撒密碼的加強版。字母表為"abcdefghijklmnopqrstuvwxyz,.!",且根據統計,t和e為英語中出現最多的字母。
破解的一般思路就是通過字母的頻率求得對應的密鑰,然後反解密文。求解過程如下。
統計字母出現
void analyze(char *c){int a[26]={0};int i=0,j;while(c[i]!='\0'){if(c[i]!='.'||c[i]!='!'||c[i]!=',')a[c[i]-'a']++;printf("%d\t",i++);}for(j=0;j<26;j++){printf("%c:%d\n",j+'a',a[j]);}}
在main中調用。
int main(){char ch1[10000];char hash[29];printf("Input paragragh:\n");gets(ch1);analyze(ch1);return 1;}
得到結果:
可治u和c為出現頻率最高的兩個字母。
在字母表中的順序:
t-19 u-20 e-4 c-2
可以列出下面的式子:
(19a+b)mod29=20
(4a+b)mod29=2
但是還不能求得a和b的值,需要用一段程式枚舉求得。
#include<stdio.h>void getA(){int a,b;for(a=0;a<20;a++){b=20-(19*a)%29;if((4*a+b)%29==2)printf("%d,%d\n",a,b);}}int main(){getA();return 1;}
得到a=7,b=3.
由於f(p)是滿足雙射關係的,即兩兩對應,可以將明暗文對應關係放在Hash表中。
char alphabet[]="abcdefghijklmnopqrstuvwxyz,.!";void createHash(char *c,int a,int b,int d){int i;char encode[29];for(i=0;i<29;i++){encode[i]=alphabet[(a*i+b)%d];printf("%c",encode[i]);}for(i=0;i<29;i++){c[encode[i]-'a']=alphabet[i];}}
這樣就可以通過密文直接hash到明文了。
解密函數就最簡單了。
void decypher(char *c,char *hashmap,int a,int b,int d){int i=0;int char_pos;//record the caractor's positionwhile(c[i]!='\0'){ char_pos=c[i]-'a'; //printf("char_pos:%d\n",char_pos);if(c[i]!=' '){printf("%c",hashmap[char_pos]);}else{printf(" ");}i++;}}
完整的程式如下:
#include<stdio.h>void analyze(char *c);void decypher(char *c,char *hashmap,int a,int b,int d);void createHash(char *c,int a,int b,int d);char alphabet[]="abcdefghijklmnopqrstuvwxyz,.!";int main(){char ch1[10000];char hash[29];printf("Input paragragh:\n");gets(ch1);analyze(ch1);printf("\nAfter decyphered:\n");createHash(hash,7,3,29);decypher(ch1,hash,7,3,29);printf("\n%s\n",ch1);return 1;}void analyze(char *c){int a[26]={0};int i=0,j;while(c[i]!='\0'){if(c[i]!='.'||c[i]!='!'||c[i]!=',')a[c[i]-'a']++;printf("%d\t",i++);}for(j=0;j<26;j++){printf("%c:%d\n",j+'a',a[j]);}}void decypher(char *c,char *hashmap,int a,int b,int d){int i=0;int char_pos;//record the caractor's positionwhile(c[i]!='\0'){ char_pos=c[i]-'a'; //printf("char_pos:%d\n",char_pos);if(c[i]!=' '){printf("%c",hashmap[char_pos]);}else{printf(" ");}i++;}}void createHash(char *c,int a,int b,int d){int i;char encode[29];for(i=0;i<29;i++){encode[i]=alphabet[(a*i+b)%d];printf("%c",encode[i]);}for(i=0;i<29;i++){c[encode[i]-'a']=alphabet[i];}printf("\n%s\n",alphabet);}
最終運行結果:
解密結果:
frequency analysis is based on the fact that, in any given stretch of written language, certain letters and combinations of letters occur withvarying frequencies. moreover, there is a charactistic distribution of letters that is roughly the same for almost
all samples of that language.