单表代替密码

凯撒密码

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
  • 实现截图:
  • 可以改进的地方:
    主要是在未知密钥解密方面,如果用任意单表替换方法加密,那么解密使用字母频率分析是需要人为介入的,在写程序中为了方便就只对移位密码使用字母频率分析做了简单解密。在已知密文长度不够情况下,字母频率可能出现相近或相同,则可以对出现频率高的取前三位来显示进行人为选择,为了方便亦没有实现这一功能。
  • 实现代码:
#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;//其它字符
    }
}

原文地址:https://www.cnblogs.com/saltedcorgi/p/12034449.html

时间: 2024-11-09 00:51:14

单表代替密码的相关文章

单表替换密码统计分析

上一篇文章提到一个任意单表替换密码算法如果k=n,那么密钥空间为k! 假设是英文字母表,密钥空间为26!,用穷举法破解不可行. 那么有其他办法吗?答案是肯定的. 我们知道语言具有一定特征的 1.偏用现象:在各种语言中,各个字母的使用次数是不一样的,有的偏高,有的偏低 2.频数:一个字母在一篇文章中出现的次数 3.使用频率:一个字母的频数除以文章的字母总数 英文字母的使用频率分布 统计分析上表得到: 某些特定的文章会含有这样的特征: 开头结尾特征,开头和结尾受到固定格式的限制. (在电影模仿游戏中

单表代替密码原理及算法实现

   要了解单表替代密码就得先了解替代密码,在这里我就做一下简单的介绍:      替代是古典密码中用到的最基本的处理技巧之一 .      替代密码是指先建立一个替换表,加密时将需要加密的明文依次通过查表,替换为相应的字符,明文字符被逐个替换后,生成无任何意义的字符串,即密文,替代密码的密钥就是其替换表.      根据密码算法加解密时使用替换表多少的不同,替代密码又可分为单表替代密码和多表替代密码.      单表替代密码的密码算法加解密时使用一个固定的替换表.单表替代密码又可分为一般单表替

古典密码-单表密码体制

如果明文中不同的位置的同一明文字母在密文中对应的密文字母相同,则称其为单表密码体制. 代表性的单表密码: 1.移位或加法密码 2.乘数或乘法密码 3.仿射密码 4.密钥短语密码 下面分别举一个例子: 1.加法密码算法: P=C=K=Zm   (Zm∈{0,1,...,m-1}) Ek(x)=x+k(mod m)=y∈C Dk(y)=y-k(mod m)=x∈P 当k=3时,该密码算法就是凯撒密码. E3(1)=1+3(mod 26)=4   1代表A,4代表D,所以就把明文A加密成D D3(4)

集成代码生成器 单表 多表 树形表 一对多 springmvc spring mybatis SSM 后台框架

获取[下载地址]   QQ: 313596790   [免费支持更新] 三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单; QQ:313596790 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块 B 集成阿里巴巴数据库连

【集成代码生成器】 单表 多表 树形表 一对多

获取[下载地址]     [免费支持更新]三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块B 集成阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.

OGG进程拆分(单表拆成多个进程)

OGG进程拆分(单表拆成多个进程) 概要: <OGG进程拆分>介绍了如何将一个入库进程中的多个表拆分到其他进程中.本篇将着重介绍如何使用多个进程同时入库一张表. 适用条件: 1)入库进程只同步一张表,但仍有延时 2)目标段主机CPU.内存压力不大,以便有足够的资源添加新的入库进程 本示例将RZG_CXI2中的HX_SB.SB_CWBB_XQYKJZZ_ZCFZB表拆分到RZG_CXI1-RZG_CXI8这8个进程中 1. 创建新添加进程的配置文件 edit  params RZG_CXI1 #

CentOS6.4 配置mysql服务器启动多个端口,同步单表数据

============================================================ ====多端口启动==== ============================================================ 创建数据目录 mkdir /usr/local/mysql/var1/ mkdir /usr/local/mysql/var2/ =================================================

利用Percona XtraBackup进行单表备份恢复

大部分情况下,使用用Percona XtraBackup进行整库的备份和恢复比较容易,此处略去:对于单表的恢复略有不同,而且对数据库版本和Percona XtraBackup的版本都有限制局限性:1.源库MySQL版本无要求,但启用了innodb_file_per_table=12.目的库开启innodb_file_per_table=1,Percona XtraDB或者MySQL5.6官方要求开启下面的两个参数,但发现5.6没有这样的变量,没去修改:innodb_expand_import=1

【集成代码生成器】 单表 多表 树形表 一对多 springmvc spring mybatis SSM 后台框架

获取[下载地址]   [免费支持更新]三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块B 集成阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Dr