单表代替密码

凯撒密码

Caser密码是古典加密的一种,由Julius Caser发明,当时发明的那种就是将26个英文字母按字母表循环移位,按顺序依次a -> d , b -> e , c -> f......根据移位不同统称为移位密码。

按照密码体制五元组

P = { a,b,c......z }
C = { a,b,c......z }
K = { 0,1,2......25 }
若是Caser密码,得到加密算法
E p = ( p + 3 ) mod 26
若移位可以是任意整数,得到加密算法
E p = ( p + k ) mod 26
得到解密算法
D c = ( c - k ) mod 26
注:mod为模算数即取余
因为密钥空间只可能有26种,而至多测试25种即能获得k,用穷举攻击是很容易实现的。

单表代替密码

若移位密码的密钥空间允许任意代替,则能得到26!种可能密钥,成为单表代替密码,急剧增大了密钥空间,可以抵挡穷举攻击,但由于语言使用的一些统计学规律仍然可以进行破解攻击。

字母频率分析解密

以英文为例,首先要把所有英文字母使用相对频率统计出来,和给定的密文的字母频率进行比较,但这种方法需要保证已知密文足够长,且在一些近似频率字母之间需要人为分析结果。
已知英文字母表单字母替换出现频率较高的五位为e、t、a、o、i。

C语言实现

  • 实现功能:
    • 命令输入错误的检查
    • 实现对所有文件的加解密
    • 实现移位密码已知密钥的加解密,大小写敏感,明密文非字母保留
    • 增加了移位密码未知密钥使用字母频度分析解密
  • 实现环境:
    • 操作系统:Windows10
    • 编译环境:Code::Blocks
  • 实现截图:
    avatar
  • 可以改进的地方:
    主要是在未知密钥解密方面,如果用任意单表替换方法加密,那么解密使用字母频率分析是需要人为介入的,在写程序中为了方便就只对移位密码使用字母频率分析做了简单解密。在已知密文长度不够情况下,字母频率可能出现相近或相同,则可以对出现频率高的取前三位来显示进行人为选择,为了方便亦没有实现这一功能。

  • 实现代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void Encrypt(int key, char infilename[], char outfilename[]);//加密函数
void Decrypt(int key, char infilename[], char outfilename[]);//解密函数
void frequency(char infilename[], char outfilename[]);//频率分析解密函数
int Character(char);//字符判断函数

int main(int argc, char *argv[]){
    if (argc != 5 || argv[1][0] != '-' || argv[1][2] != '\0'){
        printf("Usage: exename -e/-d key inputfile outputfile\nno key Usage: exename -d no inputfile outputfile");
        return;
    }
    int key = atoi(argv[2]);//密钥
    if (key == 0 ){
        if(argv[1][1] != 'd'){
            printf("Usage: exename -e/-d key inputfile outputfile\nno key Usage: exename -d no inputfile outputfile");
        }else{
            frequency(argv[3], argv[4]);
        }
    }else{
        if (key <0 || key >25) { //判断密钥合法性
            printf("The key is wrong!\n");
            return;
        }
        switch (argv[1][1]){
            case 'e':
                Encrypt(key, argv[3], argv[4]);
                break;
            case 'd':
                Decrypt(key, argv[3], argv[4]);
                break;
            default:
                break;
        }
    }
    return;
}

void Encrypt(int key, char infilename[], char outfilename[]){
    char plaintext[1000] = { 0 };//定义明文数组
    FILE *fp = NULL;//定义文件指针
    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(infilename, "r");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(plaintext, 999, fp);
    }else{//非文本文件
        fp = fopen(infilename, "rb");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(plaintext, 999, fp);//读取文件中的明文存放到数组中
    }
    fclose(fp);
    int pl = strlen(plaintext);//明文长度

    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(outfilename, "w");
    }else{//非文本文件
        fp = fopen(outfilename, "wb");
    }
    int i,value;
    for (i = 0; i < pl; i++){
        value = Character(plaintext[i]);
        if (value == -1) fprintf(fp, "%c", (plaintext[i] - 'a' + key) % 26 + 'a');
        if (value == 1)  fprintf(fp, "%c", (plaintext[i] - 'A' + key) % 26 + 'A');
        if (value == 0 || value == 255) fprintf(fp, "%c", plaintext[i]);
    }//通过移位加密原理输出密文
    fclose(fp);
    printf("The file is encrypt successful.\n");
}

void Decrypt(int key, char infilename[], char outfilename[]){
    char ciphertext[1000] = { 0 };//定义密文
    FILE *fp = NULL;//定义文件指针
    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(infilename, "r");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(ciphertext, 999, fp);
    }
    else{//非文本文件
        fp = fopen(infilename, "rb");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(ciphertext, 999, fp);
    }
    fclose(fp);
    int cl = strlen(ciphertext);//密文长度

    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(outfilename, "w");
    }
    else{//非文本文件
        fp = fopen(outfilename, "wb");
    }
    int i,value;
    for (i = 0; i < cl; i++){
        value = Character(ciphertext[i]);
        if (value == -1)fprintf(fp, "%c", (ciphertext[i] - 'a' - key + 26) % 26 + 'a');
        if (value == 1) fprintf(fp, "%c", (ciphertext[i] - 'A' - key + 26) % 26 + 'A');
        if (value == 0 || value == 255) fprintf(fp, "%c", ciphertext[i]);
    }//通过移位解密原理输出明文
    fclose(fp);
    printf("The file is decrypt successful.\n");
}

void frequency(char infilename[], char outfilename[]){
    char ciphertext[1000] = { 0 };//定义密文
    FILE *fp = NULL;//定义文件指针
    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(infilename, "r");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(ciphertext, 999, fp);
    }
    else{//非文本文件
        fp = fopen(infilename, "rb");
        if (fp == NULL) {
            printf("The file was not found!\n");
            return;
        }
        fgets(ciphertext, 999, fp);
    }
    fclose(fp);
    int cl = strlen(ciphertext);//密文长度

    int i, value, a[26] = { 0 };
    for (i = 0; i < cl; i++){
        value = Character(ciphertext[i]);
        if (value == -1) { a[ciphertext[i] - 'a']++; }
        else if (value == 1) { a[ciphertext[i] - 'A']++; }
    }//将每个字母出现的次数存放到a数组中

    int max, e;
    for (i = 0, max = 0; i<26; i++){
        if (a[i] > max) {
            max = a[i];
            e = i;
        }
    }//找到频率最高的字母即为e
    int key = (e + 22) % 26;//求出密钥值

    if (strchr(infilename, '.txt') != NULL){//文本文件
        fp = fopen(outfilename, "w");
    }
    else{//非文本文件
        fp = fopen(outfilename, "wb");
    }
    for (i = 0; i < cl; i++){
        value = Character(ciphertext[i]);
        if (value == -1)fprintf(fp, "%c", (ciphertext[i] - 'a' - key + 26) % 26 + 'a');
        if (value == 1) fprintf(fp, "%c", (ciphertext[i] - 'A' - key + 26) % 26 + 'A');
        if (value == 0 || value == 255) fprintf(fp, "%c", ciphertext[i]);
    }//通过字母频率分析解密原理输出明文
    fclose(fp);
    printf("The file is decrypt successful.\n");

}

int Character(char n){
    if (n >= 'a'&&n <= 'z') {
        return -1;//小写
    }
    else if (n >= 'A'&&n <= 'Z') {
        return 1;//大写
    }
    else if (n == ' '){
        return 0;//空格
    }
    else{
        return 255;//其它字符
    }
}

猜你喜欢

转载自www.cnblogs.com/saltedcorgi/p/12034449.html