DES加解密时产生的子密钥

DES算法共需要进行16轮迭代运算,每轮迭代运算使用一个子密钥,共需要16个子密钥。子密钥是从用户输入的初始密钥产生的,用户输入的初始密钥K64位,其中有8位用于奇偶校验,分别位于第8,16,24,32,40,48,56,64位。奇偶校验位用于检查密钥K在产生和分配以及存储过程中可能发生的错误,这样DES的密钥实际上只有56位。

加密过程生成的子密钥

首先密钥经过PC-1表置换后

         Permuted Choice 1 (PC-1)

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

将变换后的密钥分为两个部分,开始的28位称为C[0],最后的28位称为D[0]

C[i-1],D[i-1]作为下一轮i的输入(把C[i-1]复制给C[i],将D[i-1]复制给D[i]),之后同时将C[i]D[i]左移1位或2位,根据轮数值决定左移的位数。

左移位数: 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1

C[i]D[i]合成CD[i][i]

CD[i] [i]作为一个整体按下表(PC-2)变换,得到48位的K[i]

         Permuted Choice 2 (PC-2)

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

解密过程生成的子密钥

跟加密时产生子密钥的算法基本一样,只是每轮变成想右位移12

右移位数: 0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1

 

加解密过程

一、取得64位的数据,如果数据长度不足64位,应该将其扩展为64位

将64位数据按下表变换(IP)

Initial Permutation (IP)

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

将变换后的数据分为两部分,开始的32位称为L[0],最后的32位称为R[0]。用16个子密钥加密数据,初始i=1。每轮迭代都利用上一轮的L[i-1],R[i-1]。

L[i] = R[i-1];R[i] = Li-1⊕F(Ri-1,Ki);

二、F(Ri-1,Ki)实现过程:

1、将32位的R[I-1]按下表(E)扩展为48位的E[i-1]

Expansion (E)

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

2、异或E[i-1]和K[i],即E[i-1] XOR K[i]

3、S盒替换:将异或后的结果分为8个6位长的部分,每部分成为S盒的输入,跟有8个输入,对应8个S盒。如Bi=b1b2b3b4b5b6,将x=b1b6作为行号,y=b2b3b4b5作为列好,在S[i]中查找第x行第y列的值c=S[i][x][y]。将c转化为4为2进制,代替原来的Bi。经过8个替换后,产生32位比特串。

4、P盒替换:将S盒产生的32位比特串经过P盒置换,输出结果就为F(Ri-1, Ki);

     Permutation P

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

5、与L[i-1]:置换将F(Ri-1, Ki)⊕Li-1得出Ri

三、逆置换IP-1

64位的明文经过IP置换、16轮迭代运算、逆初始置换IP-1后,得到的结果极为DES加密的密文输出。

 

Final Permutation (IP**-1)

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

解密过程跟加密一样,只是加密时第i轮跟第i个子密钥异或,而解密时16子密钥被倒过来异或,只要在产生子密钥的过程中做文章就可以实现加解密过程一字不差。

以下是S盒:

S盒

         Substitution Box

S[1]

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

 

S[2]

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

 

S[3]

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

 

S[4]

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

 

S[5]

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

 

S[6]

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

 

S[7]

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

 

S[8]

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

 

 

 

 

 

#include <stdio.h>
#include 
<stdlib.h>
#include 
<string.h>
int SubKey[17][48];
int C[17][28], D[17][28], CD[17][56];
int LS[2][16= 
{
    {
1122222212222221},
    {
0122222212222221}
};
int L[17][32], R[17][32];
int en[64];
int PC1[56= 
{   
    
5749413325179,
    
1585042342618,
    
1025951433527,
    
1911360524436,
    
63554739312315,
    
7625446383022,
    
1466153453729,
    
211352820124};
int PC2[48=
{
    
1417112415,
    
3281562110,
    
2319124268,
    
1672720132,
    
415231374755,
    
304051453348,
    
444939563453,
    
464250362932};
int IP[64=
{
    
585042342618102,
    
605244362820124,
    
625446383022146,
    
645648403224168,
    
57494133251791,
    
595143352719113,
    
615345372921135,
    
635547393123157};
int E[48= 
{
    
3212345,
    
456789,
    
8910111213,
    
121314151617,
    
161718192021,
    
202122232425,
    
242526272829,
    
28293031321};
int S[8][4][16= 
{
    
//S[1]
    1441312151183106125907,
    
0157414213110612119538,
    
4114813621115129731050,
    
1512824917511314100613,
 
    
//S[2]
    1518146113497213120510,
    
3134715281412011069115,
    
0147111041315812693215,
    
1381013154211671205149,
     
    
//S[3]
    1009146315511312711428,
    
1370934610285141211151,
    
1364981530111212510147,
    
1101306987415143115212,
    
    
//S[4]
    7131430691012851112415,
    
1381156150347212110149,
    
1069012117131513145284,
    
3150610113894511127214,
    
    
//S[5]
    2124171011685315130149,
    
1411212471315015103986,
    
4211110137815912563014,
    
1181271142136150910453,
    
    
//S[6]
    1211015926801334147511,
    
1015427129561131401138,
    
9141552812370410113116,
    
4321295151011141760813,
     
    
//S[7]
    4112141508133129751061,
    
1301174911014351221586,
    
1411131237141015680592,
    
6111381410795015142312,
     
    
//S[8]
    1328461511110931450127,
    
1151381037412561101492,
    
7114191214206101315358,
    
2114741081315129035611
};
int P[32=
{
    
1672021,
    
29122817,
    
1152326,
    
5183110,
    
282414,
    
322739,
    
1913306,
    
2211425};
int RIP[64=
{
    
408481656246432,
    
397471555236331,
    
386461454226230,
    
375451353216129,
    
364441252206028,
    
353431151195927,
    
342421050185826,
    
33141949175725,
};
void LR(int * inint *outint ls)//将in左移ls位存到out 
{
    
int i;
    
for (i = 0; i < ls; i++)
        
out[28 - ls + i] = in[i];
    
for (i = ls; i < 28; i++)
        
out[i-ls] = in[i];
}
void RR(int * inint * outint ls)//将in右移ls位存到out 
{
    
int i;
    
for (i = 0; i < 28 - ls; i++)
        
out[i+ls] = in[i];
    
for (i = 28 - ls; i < 28; i++)
        
out[i - (28 - ls)] = in[i];
}
//Key是64位密钥,f为0表示该过程是产生加密的子密钥,f为1表示该过程是产生解密的子密钥 
//因为加密过程产生的16个子密钥,在解密时时倒过来的。之所以会这样主要是加密过程是左移操作,解密是右移操作 
void CreateSubKey(int * Key, int f)
{
    
int i, j;
    
for (i = 0; i < 56; i++)
        CD[
0][i] = Key[PC1[i]-1];
    
for (i = 0; i < 28; i++)
    {
        C[
0][i] = CD[0][i];
        
//printf("%d", C[0][i]);
    }//printf("--");
    for (i = 28; i < 56; i++)
    {
        D[
0][i-28= CD[0][i];
        
//printf("%d", D[0][i-28]);    
    }//printf("\n");
    for (i = 1; i <= 16; i++)
    {
        
if (f == 0)
        {
            LR(C[i
-1], C[i], LS[f][i-1]);
            LR(D[i
-1], D[i], LS[f][i-1]);
        }
        
else
        {
            RR(C[i
-1], C[i], LS[f][i-1]);
            RR(D[i
-1], D[i], LS[f][i-1]);
        }
    
//    printf("ls%d:", LS[f][i-1]);for (j = 0; j < 28; j++)printf("%d", C[i][j]);
//        printf("--");for (j = 0; j < 28; j++)printf("%d", D[i][j]);printf("\n");
    
        
for (j = 0; j < 28; j++)
        {
            CD[i][j] 
= C[i][j];
            CD[i][j
+28= D[i][j];
        }
        
for (j = 0; j < 48; j++)
        {
            SubKey[i][j] 
= CD[i][PC2[j]-1];
        }
    
//    printf("i=%d:", i);
//        for (j = 0; j < 48; j++)
//        {
//            printf("%d", SubKey[i][j]);
//        }printf("\n");
    }
}
void ip(int *mw)//IP置换,64为明文经过IP置换产生L0和R0 
{
    
int i;
    
for (i = 0; i < 64; i++)
    {
        
if (i < 32)
            L[
0][i] = mw[IP[i]-1];
        
else
            R[
0][i-32= mw[IP[i]-1];
    }
}
void ebox(int * inint *out)//e盒,in为输入,结果为out 
{
    
int i;
    
for (i = 0; i < 48; i++)
        
out[i] = in[E[i]-1];
}
void xorK(int * key, int * in)//将in与key异或 
{
    
int i;
    
for (i = 0; i < 48; i++)
        
in[i] = in[i] ^ key[i];
}
void sbox(int * inint * out)//s盒,in为输入,结果为out 
{
    
int i, x, y, z;
    
for (i = 0; i < 8; i++)
    {
        x 
= (in[0<< 1+ in[5];
        y 
= (in[1<< 3+ (in[2<< 2+ (in[3<< 1+ in[4];
        z 
= S[i][x][y];
    
//    out[0] = z & 1;
//        out[1] = (z >> 1) & 1;
//        out[2] = (z >> 2) & 1;
//        out[3] = (z >> 3) & 1;

        
out[0= (z >> 3& 1;
        
out[1= (z >> 2& 1;
        
out[2= (z >> 1& 1;
        
out[3=  z & 1;
        
in += 6out += 4
    }
}
void pbox(int * inint * out)//P盒置换in为输入,结果存于out 
{
    
int i;
    
for (i = 0; i < 32; i++
        
out[i] = in[P[i]-1];
}
void fun(int * ri, int * ki, int * out)//将R[i-1],Key[i]作为输入进行F(Ri-1,Ki)存于out 
{
    
int tmp[48], res[32];
    ebox(ri, tmp);
//将Ri进行E盒置换存于tmp 
    xorK(ki, tmp);//将tmp与子密钥异或仍存于tmp 
    sbox(tmp, res);//将tmp进行S盒置换存于res 
    pbox(res, out);//将res进行P盒置换存于out 

void xorLi(int * li, int * inint * out)//li为Li-1,将F(Ri-1,Ki)的结果作为in,out = Li-1 ^ F(Ri-1, Ki); 
{
    
int i;
    
for (i = 0; i < 32; i++)
        
out[i] = in[i] ^ li[i];
}
void Rip(int * l, int * r, int * out)//逆置换IP-1,将L16跟R16作为输入,结果存于out中 
{
    
int lr[64], i;
    
for (i = 0; i < 32; i++)
        lr[i] 
= r[i];
    
for (i = 32; i < 64; i++)
        lr[i] 
= l[i-32];
    
for (i = 0; i < 64; i++)
        
out[i] = lr[RIP[i]-1];
}
int Binary_To_Decimal(int *bit, int len)//将一个8位2进制转为一个10进制数 
{
    
int sum = 0, i;
    
for (i = 0; i < len; i++)
    {
        sum 
= sum * 2 + bit[i];
    }
    
return sum;
}
void asc(int * w, int len, char * as)//将64bit转化成一字符串 
{
    
int *= w;
    
int i, j;
    
for (i = 0, j = 0; i < 64; i += 8, p += 8, j++)
    {
        
as[j] = Binary_To_Decimal(p, 8);
    }
    
as[j] = 0;
    puts(
as);
}
void OX(int * w, int len, char * ans)//将64bit转化成16进制 
{
    
int i, j, k, a;
    
int * p = w;
    
for (i = 0, k = 0; i < len; k++, i = j)
    {
        j 
= i + 4;
        
if (j > len)
        {
            j 
= len;
        }
        a 
= Binary_To_Decimal(p + i, j - i);
        
if (a <= 9)
        {
            ans[k] 
= a + '0';
        }
        
else
        {
            ans[k] 
= a - 10 + 'A';
        }
    }
    ans[k] 
= 0;
    puts(ans);
}
int str_to_bit(char * inint * out)//将字符串in转化为二进制数组,返回二进制数组的长度 
{
    
char tmp[1000];
    
int i, j, len, k;
    strcpy(tmp, 
in);
    len 
= strlen(tmp);
    
if (len % 8 != 0)
    {
        j 
= len / 8 * 8+ 8;//printf("%d ", j);
        for (; len < j; len++)
            tmp[len] 
= ' ';
        tmp[len] 
= 0;
    }
    
//printf("%s_\n", tmp);
    for (i = 0, j = 0; tmp[i]; i++)
    {
        
for (k = 7; k >= 0; k--, j++)
        {
            
out[j] = (tmp[i] >> k) & 1;
        }
    }
    
return j;
}
void cry(int * mw, int * ans)//加解密,结果为ans 
{
    
int tmp[32];
    
int i, j;
    
char ox[100];
    ip(mw);
    
for (i = 1; i <= 16; i++)
    {
        
for (j = 0; j < 32; j++)
            L[i][j] 
= R[i-1][j];
        fun(R[i
-1], SubKey[i], tmp);
        xorLi(L[i
-1], tmp, R[i]); 
    }
    Rip(L[
16], R[16], ans);
    
for (printf("ans:\n"), i = 0; i < 64; i++)
    {
        
if (i % 8 == 0)printf("\n");
        printf(
"%d", ans[i]);
    }printf(
"\n");
    asc(ans, 
64, ox);
    
//OX(en, 64, ox);
}
void crying(int * mw, int * ans, int len)//加解密,结果为ans 
{
    
int i;
    
char ox[100];
    
for (i = 0; i < len; i += 64)
    {
        cry(mw, ans);
        mw 
+= 64, ans += 64;
    }
}
/*
learning
computer
*/
int main()
{
    
int key[64= 
    {
        
1,1,0,0,0,1,1,0,
        
1,1,0,1,1,1,1,0,
        
1,1,0,1,1,0,1,1,
        
1,1,1,0,0,0,0,1,
        
1,1,1,0,1,0,1,1,
        
1,1,1,0,1,0,0,0,
        
1,1,0,0,1,0,1,0,
        
1,1,1,0,0,1,0,0};
    
int mw[1000=
    {
        
0,1,1,0,1,1,0,0,
        
0,1,1,0,0,1,0,1,
        
0,1,1,0,0,0,0,1,
        
0,1,1,1,0,0,1,0,
        
0,1,1,0,1,1,1,0,
        
0,1,1,0,1,0,0,1,
        
0,1,1,0,1,1,1,0,
        
0,1,1,0,0,1,1,1
    };
    
int ans[1000], len;
    
char strm[1000], strk[10];
    
while (scanf("%s%s", strm, strk) - EOF)
    {
        len 
= str_to_bit(strm, mw);
        CreateSubKey(key, 
0);
        crying(mw, ans, len);
        CreateSubKey(key, 
1);
        crying(ans, ans, len);
        
//puts(ans);
    }  
    system(
"pause");
}
/*
learinglearingleari
computer
*/