DES加解密时产生的子密钥
DES算法共需要进行16轮迭代运算,每轮迭代运算使用一个子密钥,共需要16个子密钥。子密钥是从用户输入的初始密钥产生的,用户输入的初始密钥K为64位,其中有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
解密过程生成的子密钥
跟加密时产生子密钥的算法基本一样,只是每轮变成想右位移1或2位
右移位数: 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] =
{
{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1},
{0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
};
int L[17][32], R[17][32];
int en[64];
int 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};
int 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};
int 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};
int 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};
int S[8][4][16] =
{
//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
};
int P[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};
int RIP[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,
};
void LR(int * in, int *out, int 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 * in, int * out, int 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 * in, int *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 * in, int * 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 += 6, out += 4;
}
}
void pbox(int * in, int * 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 * in, int * 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 *p = 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 * in, int * 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
*/