频率法解凯撒密码

前言

  • 参考 < 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 
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值