南京航空航天大学课程设计报告课程名称密码学课程设计学院计算机科学与技术年级2014学生姓名陶超权学号*********开课时间2016 至2017 学年第一学期总成绩教师签名一、实验目的通过实现简单的古典密码算法,理解密码学的相关概念如明文(plaintext )、密文(ciphertext )、加密密钥(encryption key )、解密密钥(decryption key )、加密算法(encryption algorithm)、解密算法(decryption algorithm )等。
二、实验内容1)用C\C++语言实现单表仿射(Affine )加/解密算法;2)用C\C++语言实现统计26个英文字母出现频率的程序;3)利用单表仿射加/解密程序对一段较长的英文文章进行加密,再对明文和密文中字母出现的频率进行统计并作对比,观察有什么规律。
仿射变换:加密:()26mod )(21m k k m E c k +==解密:()26mod )(112k c k c D m k -==- 其中,k 1和k 2为密钥,k 1∈Z q ,k 2∈Z q *。
三、实验步骤1)在main 函数中构建框架,函数主要分为三部分,加密,解密,计算字符出现频率;2)加密函数encrypt(),首先需要输入两个密钥K1,k2,需要注意k2是和26互质的,所以这里用gcd()函数判断了k2与26的最大公约数,加解密都采用了文件操作,明文和密文都保存在文件中,这里加密时根据ascii 码,对大小字母分别加密,其他字符则保持不变;3)解密函数decode(),和加密函数类似,需要注意解密要用到密钥K2的逆元,所以这里用函数inverse_k2()进行了逆元的求解,另外需要注意的是解密运算过程中可能出现数值为负数的情况,在模运算下应该将它们重新置为整数。
4)计算字符频率函数calculateCharFreq(),这里只对大小字母进行统计,不计其他字符。
源代码:********************* main.cpp **********************#include<stdio.h>#include<stdlib.h>int main (){void encrypt ();void decode ();void calculateCharFreq ();int choice;printf("please input your choice:\n");printf("\t1. encrypt\n\t2.decode\n\t3.calculate character frequence\n\t4.quit&exit\n");scanf("%d",&choice);getchar();while(1){switch(choice){case1:encrypt();break;case2:decode();break;case3:calculateCharFreq();break;case4:return0;default:break;}printf("please input your choice:\n");printf("\t1. encrypt\n\t2.decode\n\t3.calculate character frequence\n\t4.quit&exit\n");scanf("%d",&choice);getchar();}return0;}*************************** encrypt.cpp ********************* #include<stdlib.h>#include<stdio.h>void encrypt(){int gcd(int,int);printf("please input secret key\n");printf("k1:");int k1,k2;scanf("%d",&k1);getchar();while(k1<0|| k1>=26){printf("illegal k1!please input agian!\n"); printf("k1:");scanf("%d",&k1);getchar();}printf("k2:");scanf("%d",&k2);getchar();while(gcd(k2,26)!=1){printf("illegal k2!please input agian!");printf("k2:");scanf("%d",&k2);getchar();}// char plainText[100]={'\0'};// char cypherText[100]={'\0'};printf("open the plain text file\n");//scanf("%s",plainText);FILE *fplain,*fcypher;if((fplain =fopen("plain.txt","a+"))==NULL){printf("can't open plain.txt!\n'");exit(0);}if((fcypher = fopen("cypher.txt","a"))==NULL) {printf("can't open cypher.txt!\n'");exit(0);}//int i;char plainText = fgetc(fplain);char cypherText;//for(i=0; plainText[i]!='\0'; i++)// printf("%c",plainText);while(plainText != EOF){// printf("old:%d\n",plainText[i]);if(65<=plainText&& plainText<=90 ){// printf(".......................");// plainText[i]-=65;cypherText = ((plainText-65)*k2+k1)%26+65;fputc(cypherText,fcypher);// printf("new:%d\n",cypherText[i]);}else if(97<=plainText && plainText<=122 ){//plainText[i]-=97;cypherText = ((plainText-97)*k2+k1)%26+97;fputc(cypherText,fcypher);// printf("new:%d\n",cypherText[i]);}else{cypherText=plainText;fputc(cypherText,fcypher);}plainText = fgetc(fplain);// printf("%c\t%c",plainText[i],cypherText[i]);}}fclose(fplain);fclose(fcypher);printf("cipher text has been written into cypher.txt!\n");// printf("%s\n\n",cypherText);}************************* decode.cpp ************************* #include<stdlib.h>#include<stdio.h>void decode(){int gcd(int,int);int inverse(int);// char cypherText[100]={'\0'};// char plainText[200]={'\0'};printf("please input secret key\n");printf("k1:");int k1,k2;scanf("%d",&k1);getchar();while(k1<0|| k1>=26){printf("illegal k1!please input agian!\n"); printf("k1:");scanf("%d",&k1);getchar();}printf("k2:");scanf("%d",&k2);getchar();while(gcd(k2,26)!=1){printf("illegal k2!please input agian!");printf("k2:");scanf("%d",&k2);getchar();}int inverse_k2 = inverse(k2);printf("open the cypher txt!\n");// scanf("%s",cypherText);FILE *fplain,*fcypher;if((fplain =fopen("plain1.txt","a"))==NULL){printf("can't open plain.txt!\n'");exit(0);}if((fcypher = fopen("cypher.txt","r"))==NULL) {printf("can't open cypher.txt!\n'");exit(0);}//int i;char cypherText = fgetc(fcypher);char plainText;//for(i=0; plainText[i]!='\0'; i++)// printf("%c",plainText);// int i;// for(i=0; cypherText[i]!='\0'; i++)while(cypherText!=EOF){// printf("old:%d\n",plainText[i]);if(65<=cypherText&& cypherText<=90 ){// printf(".......................");// plainText[i]-=65;int t= cypherText-65-k1 ;if(t<0){int i=1;while(t<0){t+=26 * i ;i++;}}plainText = ((t*inverse_k2)%26)+65;fputc(plainText,fplain);// printf("new:%d\n",cypherText[i]);}else if(97<=cypherText && cypherText<=122 ) {//plainText[i]-=97;int t= cypherText-97-k1 ;if(t<0){int i=1;while(t<0){t+=26 * i ;i++;}}plainText = ((t*inverse_k2)%26)+97;// printf("new:%d\n",plainText);fputc(plainText,fplain);}else{plainText=cypherText;fputc(plainText,fplain);}//printf("%c\t%c",plainText[i],cypherText[i]);}cypherText= fgetc(fcypher);}fclose(fplain);fclose(fcypher);printf("plain text has been written into plain1.txt!\n");// printf("%s\n\n",plainText);}int gcd(int x, int y){int t=0;//int t1=x;//int t2=y;while(y!=0){t = x%y;x = y;y = t;}//printf("%d",x);return x;}int inverse(int x){int i;for( i=0; i<26; i++){if((i*x)%26==1){break;}}// printf("%d\n",i);return i;}*********************** charFreq.cpp ************************* #include<stdio.h>#include<stdlib.h>void calculateCharFreq(){char filename[10]={'\0'};char ch;FILE * fp;float sum=0;float freq[26]={0};float charNum[26]={0};printf("please input the filename you wanna staticstic frequence:\n ");//getchar();gets(filename);//getchar();if((fp =fopen(filename,"r"))==NULL){printf("can't open %s!\n",filename);exit(0);}ch = fgetc(fp);while(ch != EOF){if('a'<=ch &&ch<='z'){charNum[ch-97]++;sum++;//printf("charNum:%f\tsum:%f\n",charNum[ch-97],sum);}else if(ch>='A'&& ch<='Z'){charNum[ch-65]++;sum++;}//printf("%c\n",ch);ch=fgetc(fp);}fclose(fp);//char t = 0;int count=0;for(int i=0;i<26;i++){freq[i]= charNum[i]/sum;//printf("charNUm:%f\tsum:%f\tfreq:%f\n",charNum[i],sum,freq[i]);printf("%c(%c):%.3f\t",i+65,i+97,freq[i]);count++;if(count==6){printf("\n");count=0;}}printf("\n\n");}四、实验结果及分析这里明文选取了普朗特的就职演说,得到明文密文各个字符的频率如下:可以看出,在明文中,出现频率最高的是e:0.123 , t:0.089, a:0.082, o:0.081, n:0.070在密文中,出现频率最高的是O:0.123, h:0.089, c:0.082, s:0.081, p:0.070经过计算可以知道字符o h c s p正是字符e t a o n的加密变换由此可知,单表仿射加密是一种线性的加密,加密后字符的统计特性没有发生变化,只是字符不同而已。