DES

来源:互联网 发布:特朗普增加军费知乎 编辑:程序博客网 时间:2024/04/29 17:19
#include<bits/stdc++.h>using namespace std;#define ENCODE true#define DECODE falseconst int//初始置换函数IPIP[64] ={    58 , 50 , 42 , 34 , 26 , 18 , 10 ,  2 ,    60 , 52 , 44 , 36 , 28 , 20 , 12 ,  4 ,    62 , 54 , 46 , 38 , 30 , 22 , 14 ,  6 ,    64 , 56 , 48 , 40 , 32 , 24 , 16 ,  8 ,    57 , 49 , 41 , 33 , 25 , 17 ,  9 ,  1 ,    59 , 51 , 43 , 35 , 27 , 19 , 11 ,  3 ,    61 , 53 , 45 , 37 , 29 , 21 , 13 ,  5 ,    63 , 55 , 47 , 39 , 31 , 23 , 15 ,  7},//末置换FP[64] ={    40 ,  8 , 48 , 16 , 56 , 24 , 64 , 32 ,    39 ,  7 , 47 , 15 , 55 , 23 , 63 , 31 ,    38 ,  6 , 46 , 14 , 54 , 22 , 62 , 30 ,    37 ,  5 , 45 , 13 , 53 , 21 , 61 , 29 ,    36 ,  4 , 44 , 12 , 52 , 20 , 60 , 28 ,    35 ,  3 , 43 , 11 , 51 , 19 , 59 , 27 ,    34 ,  2 , 42 , 10 , 50 , 18 , 58 , 26 ,    33 ,  1 , 41 ,  9 , 49 , 17 , 57 , 25},//密钥每次移动位数KM[16] ={1 ,  1 ,  2 ,  2 ,  2 ,  2 ,  2 ,  2 ,1 ,  2 ,  2 ,  2 ,  2 ,  2 ,  2 ,  1},//密钥置换PC-1PC1[56] ={    57 , 49 , 41 , 33 , 25 , 17 ,  9 ,     1 , 58 , 50 , 42 , 34 , 26 , 18 ,    10 ,  2 , 59 , 51 , 43 , 35 , 27 ,    19 , 11 ,  3 , 60 , 52 , 44 , 36 ,    63 , 55 , 47 , 39 , 31 , 23 , 15 ,     7 , 62 , 54 , 46 , 38 , 30 , 22 ,    14 ,  6 , 61 , 53 , 45 , 37 , 29 ,    21 , 13 ,  5 , 28 , 20 , 12 ,  4},//密钥的压缩置换PC-2PC2[48] ={    14 , 17 , 11 , 24 ,  1 ,  5 ,     3 , 28 , 15 ,  6 , 21 , 10 ,    23 , 19 , 12 ,  4 , 26 ,  8 ,    16 ,  7 , 27 , 20 , 13 ,  2 ,    41 , 52 , 31 , 37 , 47 , 55 ,    30 , 40 , 51 , 45 , 33 , 48 ,    44 , 49 , 39 , 56 , 34 , 53 ,    46 , 42 , 50 , 36 , 29 , 32},//S盒S_BOX[8][4][16] ={    //S1    {   {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},        {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},        {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},        {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}    },    //S2    {   {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},        {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},        {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},        {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}    },    //S3    {   {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},        {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},        {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},        {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}    },    //S4    {   {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},        {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},        {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},        {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}    },    //S5    {   {2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},        {14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},        {4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},        {11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}    },    //S6    {   {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},        {10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},        {9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},        {4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}    },    //S7    {   {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},        {13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},        {1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},        {6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}    },    //S8    {   {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},        {1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},        {7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},        {2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}    }},//扩展置换E盒E_BOX[48] ={    32 ,  1 ,  2 ,  3 ,  4 ,  5 ,     4 ,  5 ,  6 ,  7 ,  8 ,  9 ,     8 ,  9 , 10 , 11 , 12 , 13 ,    12 , 13 , 14 , 15 , 16 , 17 ,    16 , 17 , 18 , 19 , 20 , 21 ,    20 , 21 , 22 , 23 , 24 , 25 ,    24 , 25 , 26 , 27 , 28 , 29 ,    28 , 29 , 30 , 31 , 32 ,  1},//P盒P_BOX[32] ={    16 ,  7 , 20 , 21 , 29 , 12 , 28 , 17 ,     1 , 15 , 23 , 26 ,  5 , 18 , 31 , 10 ,     2 ,  8 , 24 , 14 , 32 , 27 ,  3 ,  9 ,    19 , 13 , 30 ,  6 , 22 , 11 ,  4 , 25};bool KEY[16][48];      //16个子密钥void Permutation(bool x[],int length,const int BOX[])      //置换函数,参数:待置换数据,长度,置换盒子{    bool *tmp=new bool[length];    for(int i=0;i<length;++i)        tmp[i]=x[BOX[i]-1];    for(int i=0;i<length;++i)        x[i]=tmp[i];}void GetKey(bool key[64])     //生成子密钥{    bool C[60],D[60];            //开两倍大小的数组是为了方便实现循环移位    int i,j,st;    memset(KEY,0,sizeof(KEY));    for(i = 0; i < 28; ++i)     //PC-1置换,得到28位的C0,D0    {        C[i+28] = C[i] = key[PC1[i]-1];        D[i+28] = D[i] = key[PC1[i+28]-1];    }    st = 0;                     //累计移动位数(C和D不变,为基准,加上st实现多次移位)    for(i = 0; i < 16; ++i)     //16次置换,得到16个子密钥    {        st += KM[i];        for(j = 0; j < 48; ++j)            KEY[i][j] = (PC2[j] < 28)?C[PC2[j] + st - 1]:D[PC2[j] - 29 + st];    }}void Work(bool L[32],bool R[32],bool KEY[48],int cnt)  //一轮DES{    bool X[48],RES[32];    memset(RES,0,sizeof(RES));    memset(X,0,sizeof(X));    int i,j,a,b,st,tmp;    for(i = 0; i < 48; ++i)                 //R扩展置换得到48位,和子密钥异或        X[i] = R[E_BOX[i]-1] ^ KEY[i];                                            //将异或得到的结果压缩置换成32位    for(i = 0; i < 8; ++i)                  //分为8个6位的块    {        st = i * 6;                         //每个块的起始位置        a = (X[st] << 1) + X[st + 5];       //取第1位和第6位(2进制),构成行数                                            //中间4位构成列数        b = (X[st + 1] << 3) + (X[st + 2] << 2) + (X[st + 3] << 1) + X[st + 4];        tmp = S_BOX[i][a][b];               //查找S盒        st = i * 4;                        //保存结果的数组当前存放位置的开始位置        for(j = 0; j < 4; ++j)              //拼接每次的tmp(转为4位二进制)到RES中            RES[st + (3 - j)] |= (tmp >> j)&1;    }    Permutation(RES,32,P_BOX);    for(i=0;i<32;++i)        L[i] ^= RES[i];    if (cnt == 15) return ;             //注意这里!!!!!!!!                                        //最后一轮不需要交换L和R,原因是最后拼接为64位的时候                                        //是把L作为低32位,R作为高32位的!!!!    for(i=0;i<32;++i)        swap(L[i],R[i]);}void DES(char txt[10],char enc[10],bool flag)      //DES函数,加解密共用,参数为64位明文/密文、和存放结果的数组、加解密标记{    int i,j;    bool L[32],R[32];    bool pt[64];    for(i = 0; i < 8; ++i)        for(j = 7; j >= 0; --j)                 //8位字符转换为64位2进制            pt[i * 8 + (7 - j)] = (txt[i] >> j) & 1;    Permutation(pt,64,IP);                      //初始置换    for(i = 0; i < 32; ++i)                     //拆分为两个32位        L[i] = pt[i],R[i] = pt[i + 32];    if(flag==ENCODE)                            //加密    {        for(i = 0; i < 16; ++i)                 //16轮迭代            Work(L,R,KEY[i],i);    }    else                                        //解密    {        for(i = 0; i < 16; ++i)                 //16轮迭代            Work(L,R,KEY[15-i],i);    }    for(i = 0; i < 32; ++i)                     //拼接得到64位,注意,这里的L实际上是R16,R为R15,即L16        pt[i] = L[i],pt[i + 32] = R[i];    Permutation(pt,64,FP);                      //末置换    for(i = 0; i < 8; ++i)        for(j = 7; j >= 0; --j)            enc[i] |= pt[i * 8 + (7 - j)] << j;}char Fpt[1005],Fct[1005],key[1005];void solve(bool flag){    int tmp,i,j;    bool sk[64];    char txt[10],res[10];    FILE *R,*W;    for(i = 0; i < 8; ++i)        for(j = 7; j >= 0; --j)            sk[i * 8 + (7 - j)] = (key[i] >> j) & 1;        //密钥转为64位2进制    GetKey(sk);    R = flag==ENCODE?fopen(Fpt,"r"):fopen(Fct,"r");    W = flag==ENCODE?fopen(Fct,"w"):fopen(Fpt,"w");    if(R==NULL||W==NULL) {puts("文件打开失败!"); return;}    flag==ENCODE?puts("加密结果如下:"):puts("解密结果如下:");    while((tmp = fread(txt,sizeof(txt[0]),8,R)))  //每次读取8个字符到txt中    {        for(i = tmp; i < 8; ++i) txt[i] = 0;    //不满8位,在末尾补0        memset(res,0,sizeof(res));        DES(txt,res,flag);        fwrite(res,sizeof(res[0]),8,W);        printf("%s",res);    }    puts("");    fclose(W);    fclose(R);}int main(){    int ch;    while(true)    {        puts("请选择:1.加密 2.解密");        scanf("%d",&ch);        printf("请输入存放明文的文件名(含后缀):");        scanf("%s",Fpt);        printf("请输入存放密文的文件名(含后缀):");        scanf("%s",Fct);        printf("请输入密钥:");        scanf("%s",key);        int L=strlen(key);        if(L>8) {puts("密钥长度不符合要求");continue;}        else if(L<8)    //密钥长度不足,后面添0        {            for(int i=L;i<8;++i) key[i]=0;        }        if (ch==1) solve(ENCODE);        else if (ch==2) solve(DECODE);        else break;    }    return 0;}

0 0
原创粉丝点击