C语言--分组密码DES实现

#DES算法实现

依据Fristel网络来实现

如图所示: 在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "tables.c" //数据表

//计时变量声明

clock_t start_time, finish_time;
double cord_time;

#define SIZE 400

// 2进制字符串转换成16进制字符串

void Bin2Hex(const char *In, char *Out, int Len)
{
    int times = Len / 4;
    char temp[times];
    int x = 0;
    
    for (int i = 0; i < times; i++)
    {
        x = 8 * (In[i * 4] - '0');
        x += 4 * (In[i * 4 + 1] - '0');
        x += 2 * (In[i * 4 + 2] - '0');
        x += In[i * 4 + 3] - '0';
        sprintf(temp + i, "%1x", x);
    }
    memcpy(Out, temp, times);
}

// 16进制字符串转换成2进制字符串

void Hex2Bin(char *In, char *Out, int len) 
{
    int i = 0;
    char Dict[17][5] =
        {
            "0000",
            "0001",
            "0010",
            "0011",
            "0100",
            "0101",
            "0110",
            "0111",
            "1000",
            "1001",
            "1010",
            "1011",
            "1100",
            "1101",
            "1110",
            "1111",
        };
    for (i = 0; i < len; i++)
    {
        int n = 16;
        if (In[i] >= 'a' && In[i] <= 'f')
            n = In[i] - 'a' + 10;
        if (In[i] >= 'A' && In[i] <= 'F')
            n = In[i] - 'A' + 10;
        if (In[i] >= '0' && In[i] <= '9')
            n = In[i] - '0';
        memcpy(&Out[i * 4], Dict[n], 4);
    }
    return;
}

//置换函数
//参数: In:待置换数据指针
//Out:置换输出指针
//n:置换表长度
//P:置换表指针
//说明:将输入数据的指定位置作为输出数据的第i位。指定位置即置换表第i位的十进制数。得到的输出数据的长度
//即为置换表的长度。

void myPermutation(char *In, char *Out, int n, char *P)
{
    int i = 0;
    for (i = 0; i < n; i++)
        *(Out + i) = *(In + *(P + i) - 1);
    *(Out + i) = '\0';
}

//按位异或函数
//参数:In1:二进制串1
//In2:二进制串2
//n:二进制串长度
//Out:异或结果
//说明:循环比较两个二进制串每一位,不同则为'1',相同则为'0'

void myXOR(char *In1, char *In2, int n, char *Out)
{
    int i = 0;
    for (i = 0; i < n; i++)
    {
        *(In1 + i) != *(In2 + i) ? (*(Out + i) = '1') : (*(Out + i) = '0');
    }
}

//循环左移函数
//参数: In:待移位二进制串
//Out:移位后二进制串
//n:二进制串长度
//s:循环位数
//说明:将输入二进制串移位后对应位置的值赋给输出串,为保证循环(即原二进制串的第一位变成移位后的
//最后一位),将位次相加后与串的长度做模运算。

void myShift(char *In, char *Out, int n, int s)
{
    int i = 0;
    for (i = 0; i < n; i++)
        *(Out + i) = *(In + (s + i) % n);
    *(Out + i) = '\0';
}

//生成子密钥函数
//参数: K:64位的密钥
//(*SK)[49]:得到的一轮子密钥
//说明:输入64位密钥,进行置换选择1,之后进行16轮操作得到16个子密钥,每一轮对56位分成两部分,
//进行相应位数的移位操作,之后再拼接成56位进行置换选择2,得到该轮子密钥

void mySubkey(char *K, char (*SK)[49])
{
    char out[57], C[57], D[29], e[29], t[57];
    int i = 0, j = 0;

    myPermutation(K, out, 56, *PC_1); //置换选择1
    strcpy(C, out);                   // C0
    strcpy(D, out + 28);              // D0

    for (j = 0; j < 16; j++)
    {
        myShift(C, e, 28, move_time[j]); //循环左移
        strcpy(C, e);                    // Cj
        myShift(D, e, 28, move_time[j]);
        strcpy(D, e); // Dj
        strncpy(t, C, 28);
        strncpy(t + 28, D, 28);
        myPermutation(t, *(SK + j), 48, *PC_2); //置换选择2,得到Kj
    }
}

//轮函数
//参数:  L: 第t轮的32位L
// R: 第t轮的32位R
// SK: 第t轮的48位子密钥
// t: 轮数
//说明:共进行16轮操作,每轮的32位R先进行拓展置换E变成48位,再与该轮子密钥异或,然后分成
// 8组进行S盒代换。每组通过第1,6位组成的二进制串确定S盒行号,通过第2,3,4,5位确定列号,
//找到对应的数并转为4位二进制串。8组代换拼接成32位为S盒代换结果,然后进行置换P。每轮经过
// S盒代换得到的结果与上一轮的L异或作为本轮的R,上一轮的R作为本轮的L。

void myf(char *L, char *R, char *SK, int t)
{
    int i = 0, j = 0;
    int row, col;
    char out1[49] = {0}, out2[49] = {0}, out3[33] = {0}, out4[33] = {0}, temp[33] = {0};

    printf("K%d=", t + 1);
    puts(SK);

    myPermutation(R, out1, 48, *E); //扩展置换E
    printf("E(R%d)=", t);
    puts(out1);

    myXOR(out1, SK, 48, out2); //与子密钥异或
    printf("E(R%d)^K%d=", t, t + 1);
    puts(out2);

    for (i = 0; i < 8; i++) // S盒代换
    {
        row = ((out2[i * 6] - '0') << 1) + (out2[i * 6 + 5] - '0');                                                                       //第1,6位组成行号
        col = ((out2[i * 6 + 1] - '0') << 3) + ((out2[i * 6 + 2] - '0') << 2) + ((out2[i * 6 + 3] - '0') << 1) + (out2[i * 6 + 4] - '0'); //第2,3,4,5位组成列号
        for (j = 3; j >= 0; j--)
            *(out3 + (i * 4 + 3 - j)) = ((S_Box[i][row * 16 + col] >> j) & 1) + '0'; //将取到的S盒数据填到S盒输出的指定位置,先进行十进制转二进制
    }

    *(out3 + 32) = '\0';

    printf("%d轮S盒输出=", t + 1);
    puts(out3);

    myPermutation(out3, out4, 32, *P); //置换P
    printf("f(R%d,K%d)=", t, t + 1);
    puts(out4);

    strcpy(temp, R);       //保存旧的R
    myXOR(L, out4, 32, R); //更新R
    printf("R%d=", t + 1);
    puts(R);

    strcpy(L, temp); //更新L
}

//主函数:
//说明:输入64位明文,先进行初始置换IP操作,接下来将置换输出的 64 位数据分成左右两半,左一半称为 L0 ,
//右一半称为 R0 ,各 32 位。然后进行16轮迭代,迭代过程我和轮函数写在了一起。迭代完成后再经逆IP置换得到密文。

int main()
{
    printf("**************DES数据加解密**************");

    char *M = "0123456789ABCDEF";
    char *K = "133457799bbcdff1";
    char *miwen;
    char Binarystring_1[256] = {0};
    char Binarystring_2[256] = {0};
    char mingwen[256] = {0};
    char out[65], L[33], R[33], SK[16][49], cipher[65];
    int i = 0;

    // DES加密
    //进制转换
    printf("\n原明文转换进制后为:");
    Hex2Bin(M, Binarystring_1, strlen(M));
    puts(Binarystring_1);
    M = Binarystring_1;

    printf("\n原密钥转换进制后为:");
    Hex2Bin(K, Binarystring_2, strlen(K));
    puts(Binarystring_2);
    K = Binarystring_2;

    //计时开始
    start_time = clock();

    mySubkey(K, SK);                //产生16轮子密钥
    myPermutation(M, out, 64, *IP); //初始置换IP
    printf("IP置换:");
    puts(out);

    strcpy(L, out);      // L0
    strcpy(R, out + 32); // R0
    for (i = 0; i < 16; i++)
    {
        printf("\n-------------------------------第%d轮------------------------------------\n", i + 1);
        myf(L, R, *(SK + i), i);
    }
    strncpy(out, R, 32); // L16 + R16
    strncpy(out + 32, L, 32);
    myPermutation(out, cipher, 64, *C_IP); //逆IP置换
    printf("\n密文:\n");
    puts(cipher);

    //计时结束
    finish_time = clock();
    cord_time = (double)(finish_time - start_time);
    printf("\ntime=%f ms\n", cord_time);

    printf("是否继续进行解密?(输入'Y'继续)");
    if (getchar() == 'Y')
    {
        // DES解密
        miwen = cipher;

        //计时开始
        start_time = clock();

        mySubkey(K, SK);                    //产生16轮子密钥
        myPermutation(miwen, out, 64, *IP); //初始置换IP
        printf("IP置换:");
        puts(out);

        strcpy(L, out);      // L0
        strcpy(R, out + 32); // R0
        for (i = 0; i < 16; i++)
        {
            printf("\n-------------------------------第%d轮------------------------------------\n", i + 1);
            myf(L, R, *(SK + 15 - i), i);               //解密与加密其余部分一样,只是子密钥的使用顺序相反,即原 sk+i 换成 sk+15-i 即可
        }
        strncpy(out, R, 32); // L16 + R16
        strncpy(out + 32, L, 32);
        myPermutation(out, cipher, 64, *C_IP); //逆IP置换
        printf("\n明文:\n");
        puts(cipher);

        Bin2Hex(cipher,mingwen,strlen(cipher));
        printf("转换后明文为:%s",mingwen);

        //计时结束
        finish_time = clock();
        cord_time = (double)(finish_time - start_time);
        printf("\ntime=%f ms\n", cord_time);
    }
    else
    {
        return 0;
    }
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值