前言
-
参考 < Codes and Secret Writing >
-
可知26个字母使用频率是(降序):
ETAON RISHD LFCMU GYPWB VKJXQ Z
-
所以,本文直接筛选密文中出现频率最高的字母
-
并将其与‘e’的ASCII码相减
-
即可大致推测出凯撒密码的位移值
-
具体见源码的注释部分
源码
测试用例为小王子英文版
#include<stdio.h>
// 文件名
char* ORIGINAL = "Prince.txt";
char* CYPHER = "cypher.txt";
char* RESTORE = "restore.txt";
// 字符转换部分
char* transfer(char* msg,int off){
for(int i = 0 ; msg[i] != '\0'; i++){
//区分大小写
if(msg[i]>=65 && msg[i]<=90){
msg[i] = 65+ (msg[i]-65+off+26)%26 ;
}else if(msg[i]>=97 && msg[i]<=122){
msg[i] = 97+ (msg[i]-97+off+26)%26 ;
}
}
return msg;
}
// 记录个字符出现的频率,
void recordFreq(int *freq,char* str){
for(int i = 0 ; str[i] != '\0'; i++){
freq[str[i]]++;
}
freq[' ']=0; //忽略空格
}
// 找出使用最频繁的字符
char viewFreq(int freq[]){
int max = -1;
int maxc = ' ';
for(int i = 0;i<127;i++){
// printf("%c:%d \n",i,freq[i]);
if(max < freq[i]){
max=freq[i];
maxc = i;
}
}
return maxc;
}
// 浏览文件内容
void catFile(char* fileName){
FILE *original = fopen(fileName,"r");
char str[256];
while(fgets(str,256,original))
printf("%s",str);
fclose(original);
}
// 加密部分
void encode(int key){
FILE *original = fopen(ORIGINAL,"r");
FILE *cypherText = fopen(CYPHER,"a+");
char str[256];
int freq[128]={0}; // 各字母频率
while(fgets(str,256,original)){
recordFreq(freq,str);// 统计字母频率
fputs(transfer(str,key),cypherText);// 加密后储存
}
fclose(original);
fclose(cypherText);
}
// 解密部分
void decode(){
FILE *cypherText = fopen(CYPHER,"r");
FILE *restore = fopen(RESTORE,"a+");
char str[256];
int freq[128]={0}; // 各字母频率
while(fgets(str,256,cypherText)){
recordFreq(freq,str);// 统计字母频率
// 将出现频率最高的字母,与‘e’做差
// 再取差的相反数,重新转换一次,即可实现解密。
fputs(transfer(str,-(viewFreq(freq)-'e')),restore);
}
fclose(cypherText);
fclose(restore);
}
int main(void){
int opt;
int key;
while(1){
printf("please choose [1] encode, [2] decode, [3] cat original, [4] cat cypher, [5] cat restore, [6] EXIT\n");
scanf("%d",&opt);
switch (opt)
{
case 1:
scanf("%d",&key);
encode(key);
break;
case 2:
decode();
break;
case 3:
catFile(ORIGINAL);
break;
case 4:
catFile(CYPHER);
break;
case 5:
catFile(RESTORE);
break;
case 6:
return 0;
default:
break;
}
}
return 0;
}
《小王子》原著中,部分字符出现频率
由
viewFreq()
函数内的注释部分实现
!:123
":1265
#:0
$:1
%:0
&:0
':0
(:7
):7
*:0
+:0
,:1064
-:346
.:1584
/:0
0:40
1:28
2:24
3:12
4:8
5:7
6:8
7:6
8:3
9:9
::106
;:42
<:0
=:0
>:0
?:156
@:0
A:2
B:59
C:285
D:3
E:2
F:111
G:0
H:94
I:1
J:236
K:135
L:44
M:23
N:32
O:42
P:36
Q:105
R:699
S:6
T:1
U:14
V:35
W:38
X:71
Y:13
Z:0
[:26
\:0
]:28
^:0
_:0
`:0
a:3799
b:4218
c:6692
d:1917
e:673
f:1526
g:150
h:1498
i:30
j:5353
k:847
l:1396
m:2715
n:9114
o:1318
p:1241
q:4409
r:4323
s:70
t:600
u:3169
v:1801
w:4498
x:5160
y:1195
z:71
{:0
|:0
}:0
~:0