前言
这几天上计算机安全课,讲了点密码学的东西,这次的代码是在Ubuntu上用C++进行编写的。
这次是非常简单的古典加密中的Caesar加密方法,下次应该会写对称加密DES和非对称加密RSA算法。
Caesar加密介绍
这个加密算法非常简单,方法就是把一个字符串中每一个从’a’-‘z’的字符向左或向右移动K个单位,如果大于z则从a开始。
eg.使用向右移动3位的方法
GNU Aspell is a Free and Open Source spell checker.
–>JQX Dvshoo lv d Iuhh dqg Rshq Vrxufh vshoo fkhfnhu.
具体要求
实现两个程序,分别进行加密和破解。
- 加密程序,用户给一个英文文本,选择偏移进行加密,得到加密后的文本。
- 解密程序,从可能的情况中进行发分析,判断解密出来的文本是否正确。
使用aspell检查单词拼写
因为在进行解密的时候需要判断解密出来的文本是否正确,要进行单词的拼写检查。
本来查了一下stackoverflow的一个有关问题,找到了这个enchant的github网址,但是我看了一下这个好像是底层库,并没有啥地方有这个库的使用说明(官网也没有,逃)大佬可以指点一下。
最后使用了aspell这个工具,这样的工具挺多的,如xxspell
一堆。最后使用了aspell这个工具。非常简单,具体可以参照这个arch上aspell的wiki
首先安装aspell,然后创建一个文件并写入测试字符。
1 2 3
| $ sudo apt-get install apsell $ echo "apple woold">>1.txt $ aspell check 1.txt
|
在执行之后我有错误提示
错误:No word lists can be found for the language “zh_CN”.
这是因为我的Ubuntu系统语言是中文,所以修改配置文件
1 2 3 4
| $ sudo gedit /etc/aspell.conf //在配置文件中添加一行 lang en //保存退出
|
再次使用aspell check 1.txt
就可以看到系统提示的拼写提示了。
我这儿的需求是测试有几个单词的拼写不正确,使用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12
| $ echo "Iss thisss woold apple. That" > 1.txt $ cat 1.txt //output Iss thisss woold apple. That $ cat 1.txt | aspell list //output输出字典查不到的单词 Iss thisss woold $ cat 1.txt | aspell list | wc -l //output使用管道统计字符的数量 3
|
基本使用就是这样,这个为后面的解密打下基础
加密程序
没啥好说,直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <iostream> #include <cstring> using namespace std;
int main(int argc,char **argv) { if(argc!=3){ printf("usage: ./caesar_encryption [filename] [offset]\n"); printf("\t ./caesar_encryption in.txt 3"); exit(0); }
freopen(argv[1],"r",stdin); freopen("out.txt","w",stdout);
int offset = atoi(argv[2]); char str[1025]; while (cin.getline(str,sizeof(str))) { int len=strlen(str); for(int i=0;i<len;i++){ if(str[i]>='a'&&str[i]<='z'){ if((str[i]+offset)>'z') cout<<(char)(str[i]+offset-26); else cout<<(char)(str[i]+offset); continue; } if((str[i]>='A'&&str[i]<='Z')){ if((str[i]+offset)>'Z') cout<<(char)(str[i]+offset-26); else cout<<(char)(str[i]+offset); continue; } cout<<str[i]; } cout<<endl; }
freopen("/dev/tty","w",stdout); cout<<"已完成加密"<<endl; }
|
解密
也直接上代码吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| #include <iostream> #include <cstring> using namespace std;
void executeCMD(const char *cmd, char *result) { char buf_ps[1024]; char ps[1024]={0}; FILE *ptr; strcpy(ps, cmd); if((ptr=popen(ps, "r"))!=NULL) { while(fgets(buf_ps, 1024, ptr)!=NULL) { strcat(result, buf_ps); if(strlen(result)>1024) break; } pclose(ptr); ptr = NULL; } else { printf("popen %s error\n", ps); } } int main(int argc,char **argv) { if(argc!=2){ printf("usage : ./caesar_decryption [filename]\n"); printf("\t eg. ./caesar_decryption out.txt"); }
char str[1025],filename[64]; for(int offset=1;offset<=26;offset++){ sprintf(filename,"right_%d.txt",offset); freopen(argv[1],"r",stdin); freopen(filename,"w",stdout);
while (cin.getline(str,sizeof(str))) { int len=strlen(str); for(int i=0;i<len;i++){ if(str[i]>='a'&&str[i]<='z'){ if((str[i]+offset)>'z') cout<<(char)(str[i]+offset-26); else cout<<(char)(str[i]+offset); continue; } if((str[i]>='A'&&str[i]<='Z')){ if((str[i]+offset)>'Z') cout<<(char)(str[i]+offset-26); else cout<<(char)(str[i]+offset); continue; } cout<<str[i]; } } cout<<str<<endl; cin.clear(); }
freopen("/dev/tty","w",stdout); int num[28]; char command[64],result[64]; for(int offset=1;offset<=26;offset++){ sprintf(filename,"right_%d.txt",offset); sprintf(command,"cat %s | aspell list | wc -l",filename); result[0]='\0'; executeCMD(command,result); num[offset] = atoi(result);
}
int minPos = 1,minNum=num[1]; for(int i=2;i<=26;i++){ if(num[i]<minNum){ minPos=i; minNum=num[i]; } } printf("正确的解密明文是right_%d.txt\n在字典查不到的单词数为%d\n",minPos,num[minPos]); }
|
解密前查看一下in.txt的内容,之前加密程序的结果
然后进行解密,因为之前加密是右移3位,到这儿就是右移23位可以达到相同的结果,只有UTF
在字典中没有收录,所以查不到的单词数为1
参考资料