凯撒密码算法C/C++

· · 个人记录

凯撒密码算法

引言

凯撒密码是一种替换换密码,他是经典的古典密码算法之一,它的基本思想是通过把字母移动一定的位数来实现加密和解密(所以又称移位密码)。明文中的所有字母都在字母表上向后或向前按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推X将变成A,Y变成B,Z变成C。由此可见,位数就是凯撒密码加密和解密的密钥。

凯撒密码基本原理

我们知道,字母表一共有26个英文字母,我们选择凯撒密码实现一个加密时,我们需要将某个明文字母做N位偏移得到密文,这个N最多为26,而且偏移为26时和偏移为0时一样,明文和密文对应相等,实际上可以说最大的偏移量为25,这里的偏移量是这个加密解密算法的核心,也是秘钥。

这个对应过程的计算,我们是通过求模运算来实现的。例如上述提到的偏移量为3的凯撒密码,我们可以得到这样的加密、解密公式:

加密公式: f(a)=(a+3) mod 26

解密公式: f(a)=(a-3) mod 26

上述公式是偏移量为3(秘钥为3)的凯撒密码的计算方法,同理,我们将上述式子中的3换成N,就可以得到秘钥为N的凯撒密码的计算方法了。

加密公式: f(a)=(a+N) mod 26

解密公式: f(a)=(a-N) mod 26

\def{\s}{\kern{10pt}}\boxed{ \begin{aligned} &\text{$\mathbf{定义一个环:}$} \\ &\text{对于一个整数环 $\Z_m$ } \\ &\text{集合$\Z_m= \{ 0,1,2,\dots,m-1 \} $} \end{aligned}} \def{\s}{\kern{10pt}}\boxed{ \begin{aligned} &\text{$\mathbf{移位密码(凯撒密码)}$} \\ &\text{假设$x,y,k \in \Z_{26}$ } \\ &\text{$\mathbf{加密:}e_k(x)=y\equiv x+k \mod 26$} \\ &\text{$\mathbf{解密:}d_k(y)=x\equiv y-k \mod 26$} \\ \end{aligned}}

凯撒密码加密算法

要实现凯撒密码加密算法,我们只需要写一个函数实现上面的加密公式就好。

实际上写代码的过程中,我们比较容易出错的是模运算的实现,在我们的理解中,不知不觉的把A和a都默认为第0个字符,如A偏移为3的时候,(0+3)mod 26等于3,对应的是第3个字符,这里得到的是D而不是C,类似于数组的逻辑。那么我们要怎么用代码来实现呢?

if(strI[i] >= 'A' && strI[i] <= 'Z'){
    strI[i] = ((strI[i]-'A')+numB)%26+'A';
}
else if(strI[i] >= 'a' && strI[i] <= 'z'){
    strI[i] = ((strI[i]-'a')+numB)%26+'a';
}

我们将处理一串字符的代码也封装成函数:

void Encry(char *strI,int numB){
    for(int i=0;i<strlen(strI); i++){
        if(strI[i]>= 'A'&&strI[i]<='Z'){
            strI[i]=((strI[i]-'A')+numB)%26+'A';
        }
        else if(strI[i]>='a'&&strI[i]<='z'){
            strI[i]=((strI[i]-'a')+numB)%26+'a';
        }
    }   
}

凯撒密码解密算法

在这个密码算法中,写完加密算法解密算法就简单多了。我们可以这样理解,“哪里来的回哪里去”。所以就将字母全部移动回原来的位置。

这样我们可以类比加密算法得到解密算法。

void Decry(char *strI,int numB){
    for(int i=0; i<strlen(strI); i++){
        if(strI[i] >= 'A' && strI[i] <= 'Z'){
            strI[i] = ((strI[i]-'A')+num)%26+'A'
        }
        else if(strI[i] >= 'a' && strI[i] <= 'z'){
            strI[i] = ((strI[i]-'a')+num)%26+'a';
        }
    }      
}

C/C++程序框架

对于主程序,我们只需要调用上述的加密函数、解密函数就可以了,搭主框架的时候时,应该做到良好的人机交互帮助用户使用程序。写好提示语方便用户使用。

int main(){
    char str[N];
    int model;
    int num;
    while(1){
        printf("凯撒密码:请选择模式:\n");
        printf("1.加密\n");
        printf("2.解密\n");   
        printf("3.退出\n");
        scanf("%d",&model);
        puts("");
        switch(model){
            case 1:
                printf("请输入要加密的字符串:");
                cin>>str;
                printf("请输入该密码算法的偏移数量:");
                scanf("%d",&num);
                Encry(str,num);
                puts("");
                break;
            case 2:
                printf("请输入要解密的字符串:");
                cin>>str;
                printf("请输入原密码算法的偏移数量:");
                scanf("%d",&num);
                Decry(str,num);
                puts("");
                break;
            case 3:
                return 0;
                break;
            default:
                break;
        }
    }
    return 0;
}

参考资料:

【1】《密码编码学和网络安全第五版》

【2】百度百科

【3】《深入浅出密码学》

附录:完整代码:

/*
  Warning!SYSTEM ERROR!!The system is about to collapse!!!   Caesar Key: 5
=>Bfwsnsl!XDXYJR JWWTW!!Ymj xdxyjr nx fgtzy yt htqqfuxj!!!
*/
#include<bits/stdc++.h>
#define N 100005
using namespace std;
void Encry(char *strI,int numB,int model);
void Decry(char *strI,int numB,int model);
int Read();
int FileOut(char *strI);
int fileout(char *strI);
char str[N];
char str1[N];
int model;
int numB;
int pd;
int sj;
int len;
int main(){
    while(1){
        printf("凯撒密码:\n请选择模式:\n");
        printf("1.加密\n");
        printf("2.解密\n");
        printf("3.强制解密\n");
        printf("4.随机加密\n");
        printf("5.退出\n");
        model=Read();
        printf("\n");
        switch(model){
            case 1:
                printf("请输入要加密的字符串:");
                cin.getline(str,100000);
                printf("请输入该密码算法的偏移数量:");
                numB=Read();
                Encry(str,numB,model);
                printf("\n");
                break;
            case 2:
                printf("请输入要解密的字符串:");
                cin.getline(str,100000);
                printf("请输入原密码算法的偏移数量:");
                numB=Read();
                Decry(str,numB,model);
                printf("\n");
                break;
            case 3:
                printf("请输入要解密的字符串:");
                cin.getline(str,100000);
                len=strlen(str);
                for(int i=1;i<=25;++i){
                    for(int j=0;j<len;++j){
                        str1[j]=str[j];
                    }
                    Decry(str1,i,2);
                    printf("该密码算法的偏移数量为:%d\n",i);
                    printf("是否继续?\n");
                    printf("1.是\n");
                    printf("0.否\n");
                    pd=Read();
                    if(!pd){
                        break;
                    }
                }
                break;
            case 4:
                printf("请输入要加密的字符串:");
                cin.getline(str,100000);
                srand((unsigned)time(NULL));
                sj=rand()%26;
                Encry(str,sj,1);
                printf("是否输出密码算法的偏移数量?\n");
                printf("1.是\n");
                printf("0.否\n");
                pd=Read();
                if(pd){
                    printf("密码算法的偏移数量为:%d\n",sj);
                }
                printf("\n");
                break;
            case 5:
                printf("按任意键退出......");
                getchar();
                return 0;
                break;
            default:
                break;
        }
    }
}
void Encry(char *strI,int numB,int model){
    if(model==1){
        for(int i=0;i<strlen(strI);++i){
            if(strI[i]>='A'&&strI[i]<='Z'){
                strI[i]=((strI[i]-'A')+numB)%26+'A';
            }
            else if(strI[i]>='a'&&strI[i]<='z'){
                strI[i]=((strI[i]-'a')+numB)%26+'a';
            }
        }
        printf("加密完成:%s\n",strI);
        FileOut(strI);
        printf("已输出到文件!\n");
    }
    else{
        printf("该模式不支持此项功能!\n");
    }
}
void Decry(char *strI,int numB,int model){
    if(model==2){
        for(int i=0;i<strlen(strI);++i){
            if(strI[i]>='A'&&strI[i]<='Z'){
                strI[i]=((strI[i]-'A')-numB)%26+'A';
            }
            else if(strI[i]>='a'&&strI[i]<='z'){
                strI[i]=((strI[i]-'a')-numB)%26+'a';
            }
        }
        printf("解密完成:%s\n",strI);
        fileout(strI);
        printf("已输出到文件!\n");
    }
    else{
        printf("该模式不支持此项功能!\n");
    }
}
int FileOut(char *strI){
    FILE *fp=NULL;
    int iWrite=0;
    int len=strlen(strI);
    if(strI==NULL||len==0){
        return false;
    }
    if((fp=fopen("凯撒密码密文.txt","w" ))==NULL){ 
        return false;
    }
    iWrite=fwrite(strI,1,len,fp);
    fclose(fp);
    if(iWrite>0){
        return true;
    }
    else{
        return false;
    }
}
int fileout(char *strI){
    FILE *fp=NULL;
    int iWrite=0;
    int len=strlen(strI);
    if(strI==NULL||len==0){
        return false;
    }
    if((fp=fopen("凯撒密码原文.txt","w" ))==NULL){
        return false;
    }
    iWrite=fwrite(strI,1,len,fp);
    fclose(fp);
    if(iWrite>0){
        return true;
    }
    else{
        return false;
    }
}
int Read(){
    int x=0;
    char ch=getchar();
    bool flag=false;
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            flag=true;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    if(flag){
        x=-x;
    }
    return x;
}