DES

#include<bits/stdc++.h>
using namespace std;
#define ENCODE true
#define DECODE false

const int
//初始置换函数IP
IP[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-1
PC1[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-2
PC2[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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值