理解并实践DES算法(附有代码)

一、简要介绍

DES算法采用位操作(如置换、选择、异或等)和S盒替换等方式,将64位的明文和56位的密钥通过16轮迭代运算,生成64位的密文。解密过程则是加密过程的逆向操作。

二、困难点主要有:

1. 复杂的运算步骤:DES算法包括了多种不同的运算步骤,如初始置换、扩展置换、S盒替换、P盒置换等,每一步都有其特定的逻辑和功能,需要花费一些时间去理解和记忆。

2. 位操作:DES算法大量使用了位操作,如异或、左移、右移等,对位操作不熟悉的人来说可能会感到有些困难。

3. 密钥的生成和处理:DES算法的密钥生成包括置换选择、左移、右移等步骤,理解这些步骤并掌握其原理是学习DES算法的一个挑战。

三、DES算法的重要部分主要有:

1. 初始置换和逆初始置换:这是DES算法的第一步和最后一步,它们保证了算法的对称性。

2. 扩展置换:这一步将32位数据扩展为48位,为后续与密钥进行异或运算做准备。

3. S盒替换:这是DES算法的核心部分,它通过一系列复杂的操作将48位的数据转化为32位,增加了破解的难度。

4. P盒置换:这一步将S盒替换的结果进行再次置换,增加了算法的混淆性。

5. 密钥的生成:这是每轮迭代中都会用到的部分,密钥的生成过程直接影响到整个加密的安全性。

理解上述的各个部分,并掌握它们之间的联系,是理解和掌握DES算法的关键。

四、代码实现

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

//DES算法把64位的明文输入块变为64位的密文输出块

使用的密钥也是64位,其功能是把输入的64位数据块按位重新组合,

并把输出分为L0、R0两部分,每部分各长32位,

其置换规则如下

const static char IP_Table[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 };

//逆置换规则如下表

const static char IP_Table2[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 };

int s1[4][16] = { { 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[4][16] = { { 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[4][16] = { { 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[4][16] = { { 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, 3 },{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } },

s5[4][16] = { { 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[4][16] = { { 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][16] = { { 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[4][16] = { { 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 } };

const static char e[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 };    //E

int pp[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 };     //P

const static char pc_1[64] = { 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 };

const static char pc_2[64] = { 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 };

const static char moveleft[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

void print2(unsigned char n) {

    char i = 0;

    int a;

    for (i = 0; i < 8; i++) {

         a = n >> (7 - i);

         a = a & 1;

         printf("%d", a);

    }

}

void unit642array(unsigned long long int a, unsigned char t[]) {

    for (int i = 0; i < 64; i++)

         t[i] = (a >> (63 - i)) & 0x1;

}

unsigned long long int array2unit64(unsigned char t[]) {

    unsigned long long int a = 0;

    for (int i = 0; i < 64; i++) {

         a = a << 1;

         a = a ^ t[i];

    }

    return a;

}

void unit648array(unsigned long long int M, unsigned char p[]) {

    int i, j;

    unsigned long long int a = 0;

    for(i = 0; i < 8; i++)

         for (j = i * 8; j < 8 * (i + 1); j++) {

             a = (M >> (63 - j)) & 0x1;

             p[i] = p[i] << 1;

             p[i] = p[i] ^ a;

         }

}

unsigned long long int array8unit64(unsigned char p[]) {

    int i;

    unsigned long long int m = 0;

    for (i = 0; i < 8; i++) {

         m = m << 8;

         m = m ^ p[i];

    }

    return m;

}

void unit1array8(unsigned char p,unsigned char n[]) {

    int i;

    for (i = 7; i >= 0; i--) {

         n[i] = p & 1;

         p = p >> 1;

    }

}

void print2_64(unsigned long long int n) {

    unsigned char p[8];

    int i;

    unit648array(n, p);

    for (i = 0; i < 8; i++) {

         print2(p[i]);

    }

}

void initIPtable(unsigned long long int T[][256]) {

    for (int i = 0; i < 8; i++)

         for (int j = 0; j < 256; j++) {

             unsigned long long int a = j;

             a = a << ((7 - i) * 8);

             unsigned char s1[64];

             unsigned char s2[64] = { 0 };

             unit642array(a, s1);

             for (int k = 0; k < 64; k++)

                  s2[k] = s1[IP_Table[k] - 1];

             a = array2unit64(s2);

             T[i][j] = a;

         }

}

void initIPtable2(unsigned long long int T[][256]) {

    for (int i = 0; i < 8; i++)

         for (int j = 0; j < 256; j++) {

             unsigned long long int a = j;

             a = a << ((7 - i) * 8);

             unsigned char s1[64];

             unsigned char s2[64] = { 0 };

             unit642array(a, s1);

             for (int k = 0; k < 64; k++)

                  s2[k] = s1[IP_Table2[k] - 1];//先把a拆成64个1字节的数,再根据IP_Table[k] 求出在s2数组中k位置的值

             a = array2unit64(s2);

             T[i][j] = a;

         }

}

//IP置换

unsigned long long int IP(unsigned long long int T[][256], unsigned char p[], unsigned long long int m) {

    int i;

    for (i = 0; i < 8; i++)

         m= m ^ T[i][p[i]];

    return m;

}

//扩展运算(E盒)

void ee(unsigned char p[], unsigned long long int R) {

    int i, j;

    unsigned char t[64], a = 0;

    unit642array(R, t);

    for (i = 0; i < 8; i++) {

         for (j = 0; j < 8; j++)

             if (j != 0 && j != 1) {

                  a = t[e[6 * i + j - 2] - 1];

                  p[i] = (p[i] << 1) ^ a;

             }

    }

}

//选择压缩运算(S盒)将48bits分为8*6bit 根据‘8个6进4出s盒’进行压缩

//ps:对第几个6bit进行压缩就使用第几个s盒

void sbox(unsigned char p[]) {

    unsigned char i, j, n[8];

    int k;

    for (k = 0; k < 8; k++) {

         unit1array8(p[k], n);

         i = n[2];

         i = i << 1;

         i = i ^ n[7];

         j = n[3];

         j = j << 1;

         j = j ^ n[4];

         j = j << 1;

         j = j ^ n[5];

         j = j << 1;

         j = j ^ n[6];

         switch (k) {

         case 0:

             p[0] = s1[i][j]; break;

         case 1:

             p[1] = s2[i][j]; break;

         case 2:

             p[2] = s3[i][j]; break;

         case 3:

             p[3] = s4[i][j]; break;

         case 4:

             p[4] = s5[i][j]; break;

         case 5:

             p[5] = s6[i][j]; break;

         case 6:

             p[6] = s7[i][j]; break;

         case 7:

             p[7] = s8[i][j]; break;

         };

    }

}

//置换运算(p盒)

//置换之后就将结果与L0/H0进行异或

unsigned long long int pchange(unsigned char p[]) {

    int i, j;

    unsigned char t[64], t2[64] = {0};

    unsigned long long int m2 = 0;

    for (i = 0; i < 8; i++) {

         m2 = m2 << 4;

         m2 = m2 ^ p[i];

    }

    m2 = m2 << 32;

    unit642array(m2, t);

    for (j = 0; j < 32; j++)

         t2[j] = t[pp[j] - 1];

    return array2unit64(t2);

}

//异或运算

unsigned long long int diffor(unsigned long long int m1, unsigned long long int m2) {

    return m1 ^ m2;

}

void addzero(unsigned char kk[]) {

    int i;

    unsigned long long int k;

    k = array8unit64(kk);

    for (i = 0; i < 8; i++) {

         kk[i] = k >> (57 - i * 7) << 1;

    }

}

unsigned long long int changepc_1(unsigned long long int k) {

    unsigned char t[64],t2[64];

    int i;

    unit642array(k, t);

    for (i = 0; i < 64; i++)

         t2[i] = t[pc_1[i] - 1];

    return array2unit64(t2);

}

unsigned long long int changepc_2(unsigned long long int k) {

    unsigned char t[64], t2[48];

    int i;

    unit642array(k, t);

    for (i = 0; i < 48; i++)

         t2[i] = t[pc_2[i] - 1];

    return array2unit64(t2);

}

//密钥扩展

unsigned long long int producek(unsigned long long int k, int a) {

    int i;

    unsigned char  t[64] = {0}, k2, t2[64] = {0};

    unsigned long long int L, R;

    k = changepc_1(k);

    L = k >> 36 << 36;

    R = k << 28;

    for (i = 0; i < moveleft[a]; i++) {

         unit642array(R, t);

         k2 = t[0];

         R = R << 1;

         unit642array(R, t2);

         t2[27] = t[0];

         R = array2unit64(t2);

         unit642array(L, t);

         k2 = t[0];

         L = L << 1;

         unit642array(L, t2);

         t2[27] = t[0];

         L = array2unit64(t2);

    }

    k = L ^ (R >> 28);

    k = changepc_2(k);

    k = k >> 16 << 16;

    return k;

}

int main() {

    int i, j, a;

    unsigned long long int M, k, m = 0, R, L, m2 = 0, m3;

    unsigned char p[8], p2[8] = {0}, p3[8] = {0}, MM[9] = {0}, kk[9] = {0}, s1[64], s2[8] = {0};

    unsigned long long int T[8][256] = {0};

    printf("请输入明文M:");

    scanf("%s", MM);

    M = array8unit64(MM);

    printf("请输入密钥k:");

    scanf("%s", kk);

    addzero(kk);

    k = array8unit64(kk);

    initIPtable(T);

    unit648array(M, p);

    m = IP(T, p, m);

    L = m >> 32 <<32;

    R = m << 32;

    for (j = 0; j < 16; j++) {

         k = producek(k, j);

         ee(p2, R);

         unit642array(k, s1);

         for (i = 0; i < 8; i++) {

             for (a = 0; a < 6; a++) {

                  s2[i] = s2[i] << 1;

                  s2[i] = s2[i] ^ s1[i * 6 + a];

             }

             p2[i] = p2[i] ^ s2[i];

         }

         sbox(p2);

         m2 = pchange(p2);

         m3 = diffor(m2, L);

         R = m3;

         L = R;

    }

    m3 = R;

    R = L;

    L = m3;

    m = L ^ (R >> 32);

    initIPtable2(T);

    IP(T, p, m);

    printf("密文为:");

    print2_64(m);

}

五、实现代码后得出以下心得体会:

困难点:
1. Bit Manipulation: DES算法涉及到大量的位操作,包括位移、异或等操作,对理解和掌握位操作有较高的要求。

2. 密钥扩展: 密钥扩展是DES算法的关键部分,需要将64位的密钥扩展为16个48位的子密钥,这一过程中涉及到PC-1和PC-2选择、左移等操作,实现起来相对复杂。

3. S-boxes substitution: 这是DES算法的核心部分,需要对数据进行非线性替换,这一过程中涉及到多个S盒,每个S盒都有不同的替换规则,理解和实现起来较为困难。

4. Feistel结构: DES算法采用Feistel结构,这导致每一轮的加密过程都需要进行分组、扩展、替换、置换等多个步骤,实现起来需要对整个流程有清晰的理解。

5. Initial and final permutations: DES算法的开始和结束都需要进行置换操作,这两个置换的规则不同,需要对这两个过程有清晰的理解。

六、总结:

1. 密钥扩展: 将64位的密钥扩展为16个48位的子密钥,这是DES算法加密过程中使用的密钥。

2. Feistel结构: DES算法的每一轮加密都遵循Feistel结构,包括分组、扩展、替换和置换等步骤。

3. S-boxes substitution: 这是DES算法的核心部分,通过对数据进行非线性替换,增加了加密的复杂度。

4. Initial and final permutations: 这两个操作在DES算法的开始和结束进行,分别对数据进行置换,保证了数据的混乱和扩散。

5. 16 rounds of encryption: DES算法进行16轮加密,每一轮加密都使用不同的子密钥,加大了破解的难度。

ps:需要注意的是,DES算法虽然历史悠久,是一种经典的对称加密算法,但由于其密钥长度较短,容易受到暴力破解的攻击,因此在需要更高安全性的场合,推荐使用AES等更安全的加密算法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xixixi77777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值