📄 des算法实现过程分析 之 c++实践篇.txt
字号:
// 标 题: DES算法实现过程分析 之 C++实践篇
// DES算法实现过程分析
// 引自绿色兵团(http://www.isbase.com)
// dapingguo修改并算法用C++实现
#include <stdio.h>
void expand(const unsigned char in[32],unsigned char out[48])
{
unsigned char table4[48]={ 31, 0, 1, 2, 3, 4,
3, 4, 5, 6, 7, 8,
7, 8, 9, 10, 11, 12,
11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20,
19, 20, 21, 22, 23, 24,
23, 24, 25, 26, 27, 28,
27, 28, 29, 30, 31, 0 };
for (int i=0;i<48;i++) out[i]=in[table4[i]]; }
void keys(const unsigned char password[8], unsigned char K[16][48])
//根据密钥password计算16个子密钥K[16][48]
{
int i,j;
unsigned char key[64];
//1. 处理密钥:
//1.1 从用户处获得64位密钥.(每第8位为校验位,为使密钥有正确的奇偶校
// 验,每个密钥要有奇数个'1'位.),得key[64];
for (i=0;i<64;i++) {
int byte=i/8;
int bit=i%8;
int value=password[byte];
value>>=bit; value&=1;
key[i]= value?1:0;
}
//1.2 具体过程:
//1.2.1 对密钥key[64]实施换位变换得密钥keyT[56].
// (keyT[i]=key[j]; i=0..55, j值如下表,显然,忽略了校验位)
unsigned char keyT[56];
unsigned char table1[56]={56, 48, 40, 32, 24, 16, 8, 0,
57, 49, 41, 33, 25, 17, 9, 1,
58, 50, 42, 34, 26, 18, 10, 2,
59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6,
61, 53, 45, 37, 29, 21, 13, 5,
60, 52, 44, 36, 28, 20, 12, 4,
27, 19, 11, 3 };
for (i=0; i<56; i++) keyT[i]=key[table1[i]];
//1.2.2 把变换后的密钥等分成两部分,前28位记为C, 后28位记为D.
unsigned char *C=keyT;
unsigned char *D=keyT+28;
//1.2.3 计算子密钥(共16个), 从i=0开始。
for (i=0; i<16; i++){
//1.2.3.1 分别对C,D作循环左移
// 每次循环左移位数如下表所示:
// 循环次数i 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15
// 左移位数 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
char loop[16]= {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
unsigned char tmp[28];
int n=loop[i];
int j;
for (j=0; j<28; j++) tmp[j]=C[(j+28-n)%28];
for (j=0; j<28; j++) C[j]=tmp[j];
for (j=0; j<28; j++) tmp[j]=D[(j+28-n)%28];
for (j=0; j<28; j++) D[j]=tmp[j];
//1.2.3.2 串联C,D,得到一个56位数CD[56],然后对此数作如下换位变换
// 以产生48位子密钥K[i][48]。
unsigned char *CD=keyT;
unsigned char table2[48]=
{13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
for (j=0;j<48;j++)
K[i][j]=CD[table2[j]];
//1.2.3.3 按以上方法计算出16个子密钥K[16][48]。
}
}
void des(const unsigned char datain[8], unsigned char dataout[8],
const unsigned char K[16][48], const unsigned char mode)
//根据密钥K[16][48]和mode加密或解密数据块data[8],
//处理后的数据放在dataout[8]中
{
//2.对64位数据块的处理:
//2.1 把数据分成64位的数据块DATA[64],不够64位的以适当的方式填补。
unsigned char DATA[64];
int i,j;
for (i=0;i<64;i++) {
int byte=i/8;
int bit=i%8;
int value=datain[byte];
value>>=bit;
value&=1;
DATA[i]= value;
}
//2.2 对数据块DATA[64]作换位变换为data[64]。
unsigned char data[64];
unsigned char table3[64]= { 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,
56, 48, 40, 32, 24, 16, 8, 0,
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6 };
for (i=0;i<64;i++) data[i]=DATA[table3[i]];
//2.3 将变换后的数据块等分成前后两部分,前32位记为L[0],后32位记为R[0]。
unsigned char L[17][32];
unsigned char R[17][32];
for (i=0; i<32; i++) L[0][i]=data[i];
for (i=0; i<32; i++) R[0][i]=data[i+32];
unsigned char 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 };
unsigned char R_[48];
//2.4 用16个子密钥对数据加密。从i=0开始。
for (i=0; i<16; i++) {
//2.4.1 根据下面表格扩充32位数据R[i]为48位数据R'。
expand(R[i],R_);
//2.4.2 用R'[48]与K[i][48]作异或运算。
for (j=0;j<48;j++)
if (mode) R_[j]^=K[i][j];
else R_[j]^=K[16-1-i][j];
//2.4.3 把所得的48位数分成8个6位数B[8]。
// 1-6位为B[0],7-12位为B[1],……,43-48位为B[7]。
unsigned char B[8];
for (j=0; j<8; j++){ B[j]=0;
for (int k=0; k<6; k++)
B[j]|=(R_[j*6+k]<<(6-1-k));}
//2.4.4 用S密箱里的值替换B[j]。
// 从j=0开始。S密箱里的值为4位数,共8个S密箱
for (j=0; j<8; j++){
//2.4.4.1 取出B[j]的第1和第6位串联起来成一个2位数,记为m.。
// m即是S密箱里用来替换B[j]的数所在的列数。
//2.4.4.2 取出B[j]的第2至第5位串联起来成一个4位数,记为n。
// n即是S密箱里用来替换B[j]的数所在的行数。
int m=0; int n=0;
m|=(B[j]&0x1); m|=((B[j]>>4)&0x2);
n=(B[j]>>1); n&=0x0f;
//2.4.4.3 用S密箱里的值S[j][m][n]替换B[j]。
B[j]=s[j][m][n];
//2.4.4.4 返回2.4.4.1直至8个数据块都被替换。
}
//2.4.5 把B[0]至B[7] 顺序串联起来得到一个32位数tmp[32]。
unsigned char tmp[32];
for (j=0;j<32; j++)
tmp[j]= (B[j/4]>> (4-1-(j%4)))&1;
unsigned char table5[32]={
15, 6, 19, 20, 28, 11, 27, 16,
0, 14, 22, 25, 4, 17, 30, 9,
1, 7, 23, 13, 31, 26, 2, 8,
18, 12, 29, 5, 21, 10, 3, 24};
unsigned char tmp1[32];
// 对tmp[32]做作换位变换为tmp1[32]。
for (j=0;j<32;j++)
tmp1[j]=tmp[table5[j]];
//2.4.6 把得到的结果tmp1[32]与L[i][32]作异或运算。
// 把计算结果賦给R[i+1][32]。
for (j=0;j<32;j++)
R[i+1][j]=L[i][j]^tmp1[j];
//2.4.7 把R[i][32]的值賦给L[i+1][32]。
for (j=0;j<32;j++)
L[i+1][j]=R[i][j];
//2.4.8 从2.4.1循环执行,直到K[15]也被用到。
}
//2.5 把R[16]和L[16] 顺序串联起来得到一个64位数tmp2[64]。
unsigned char tmp2[64];
for (i=0;i<32;i++) tmp2[i]=R[16][i];
for (i=32;i<64;i++)tmp2[i]=L[16][i-32];
// 对这个数实施2.2变换的逆变换得out[64]。
unsigned char out[64];
for (i=0;i<64;i++) out[table3[i]]=tmp2[i];
//2. 6 out[64]即为加密过的64位数据.
for (i=0; i<8;i++){
dataout[i]=0;
for (j=0; j<8; j++)
dataout[i]|=(out[i*8+j]<<j);}
}
//以下是测试部分
void main()
{
unsigned char KEY[8]= "12345678";
unsigned char source[8]="abcdefgh";
unsigned char target[8];
unsigned char K[16][48];
keys(KEY,K);
printf("======================");
printf("\nPassword=%s\n",KEY);
printf("\nSource ");
for (int i=0;i<8;i++)
printf("%02X ",source[i]&0x0ff);
printf("\n ");
for (i=0;i<8;i++)
printf("%c ",source[i]);
#define ENCRYPT 1
des(source, target,K,ENCRYPT);
printf("\nEncrypt ");
for (i=0;i<8;i++)
printf("%02X ",target[i]&0x0ff);
printf("\n ");
for (i=0;i<8;i++)
printf("%c ",target[i]);
#define DECRYPT 0
des(target,source, K,DECRYPT);
printf("\nDecrypt ");
for (i=0;i<8;i++)
printf("%02X ",source[i]&0x0ff);
printf("\n ");
for (i=0;i<8;i++)
printf("%c ",source[i]);
printf("\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -