DES对称加密纯C语言实现

 如有错误和不足之处,敬请指正

#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

//初始置换IP表
static const short IP[] = {
	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
};

//逆初始置换IP-1表
static const short IP_M1[] = {
	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,
	32, 0, 40, 8,  48, 16, 56, 24
};

//拓展置换表E
static const short E[] = {
	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
};

//S盒
static const unsigned char Sn[][64] = {
	/*S1盒*/
	{
	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盒*/
	{
	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盒*/
	{
	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盒*/
	{
	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
	},
	/*S5盒*/
	{
	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盒*/
	{
	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,  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盒*/
	{
	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
	}
};

//f函数内的置换P
static const short P[] = {
	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
};

//初始密钥置换PC-1
static const short PC_1[] = {
	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
};

//PC-2的轮密钥置换
static const short PC_2[] = {
	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
};

//加密时每轮密钥循环左位移的大小
static const short LSn[] = {
	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};

//解密时每轮密钥循环右位移的大小
static const short RSn[] = {
	0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};

//将src指向的bit位内存转换到dst中,每个bit位转换成一个byte,内容不变,input_length代表要转换的bit位总长度
static int bits2bytes(unsigned char* dst, unsigned char* src, unsigned int input_length) {
	unsigned int i, j;
	unsigned int tl = input_length >> 3;
	unsigned int re = input_length & 0x07;

	for (i = 0, j = 0; i < tl; ++i) {
		dst[j++] = src[i] >> 7;
		dst[j++] = src[i] >> 6 & 0x01;
		dst[j++] = src[i] >> 5 & 0x01;
		dst[j++] = src[i] >> 4 & 0x01;
		dst[j++] = src[i] >> 3 & 0x01;
		dst[j++] = src[i] >> 2 & 0x01;
		dst[j++] = src[i] >> 1 & 0x01;
		dst[j++] = src[i] & 0x01;
	}

	if (re) {
		for (i = 0; i < re; ++i) {
			dst[j++] = src[tl] >> (7 - i) & 0x01;
		}
	}

	return 0;
}

//将src指向的byte内存转换到dst中,每8个byte位转换成一个byte,src指向的内存内容必须为0或1,input_length代表要转换的byte总长度
static int bytes2bits(unsigned char* dst, unsigned char* src, unsigned int input_length) {
	unsigned int i, j, k;
	unsigned int tl = input_length >> 3;
	unsigned int re = input_length & 0x07;
	unsigned char tbyte;
	for (i = 0, j = 0; i < tl; ++i) {
		tbyte = 0;
		tbyte += src[j++] << 7;
		tbyte += src[j++] << 6;
		tbyte += src[j++] << 5;
		tbyte += src[j++] << 4;
		tbyte += src[j++] << 3;
		tbyte += src[j++] << 2;
		tbyte += src[j++] << 1;
		tbyte += src[j++];
		dst[i] = tbyte;
	}

	if (re) {
		for (k = 0, tbyte = 0; k < re; ++k) {
			tbyte += src[j++] << (7 - i);
		}
		dst[i] = tbyte;
	}

	return 0;
}

//des加密,data为明文——8bytes,key为密钥——8bytes,ciphertext为输出密文——8bytes
int des_encrypt(unsigned char* data, unsigned char* key, unsigned char* ciphertext) {
	long int i, j, k, m;
	unsigned char bdata[64];
	unsigned char bkey[64];
	unsigned char darr64[64];
	unsigned char* Ln;
	unsigned char* Rn;
	unsigned char ERn[48];
	unsigned char pRn[32];

	unsigned char karr[56];
	unsigned char Cn[56];
	unsigned char Dn[56];
	unsigned char* pfCn = (unsigned char*)(&Cn);
	unsigned char* pfDn = (unsigned char*)(&Dn);
	unsigned char tCnDn[56];
	unsigned char kn[48];
	unsigned char tS;

	short int mapS;

	if (data == NULL || key == NULL || ciphertext == NULL) {
		goto fail;
	}

	//先将明文和密钥拆分每个bit位到数组中
	bits2bytes(bdata, data, 64);
	bits2bytes(bkey, key, 64);

	//初始IP置换
	for (i = 0; i < 64; ++i) {
		darr64[i] = bdata[IP[i]];
	}

	//划分Ln和Rn
	Ln = darr64;
	Rn = darr64 + 32;

	//密钥初始置换
	for (i = 0; i < 56; ++i) {
		karr[i] = bkey[PC_1[i]];
	}

	//将初始替换后的密钥分为左半部分和右半部分,分别复制两遍到另一个数组中,这样有利于移位
	memcpy(Cn, karr, 28);
	memcpy((unsigned char*)(&Cn) + 28, karr, 28);
	memcpy(Dn, (unsigned char*)(&karr) + 28, 28);
	memcpy((unsigned char*)(&Dn) + 28, (unsigned char*)(&karr) + 28, 28);

	//16次轮加密
	for (i = 0; i < 16; ++i) {
		//调整指针位置,实际上实现的就是密钥编排中的移位
		pfCn += LSn[i];
		pfDn += LSn[i];

		//调整完成后重新组一个数组
		memcpy(tCnDn, pfCn, 28);
		memcpy((unsigned char*)(&tCnDn) + 28, pfDn, 28);

		for (j = 0; j < 48; ++j) {
			//密钥编排中的PC-2置换
			kn[j] = tCnDn[PC_2[j]];
			//同时实现拓展置换E
			ERn[j] = Rn[E[j]];
			//轮密钥和拓展置换后结果进行异或
			ERn[j] = ERn[j] ^ kn[j];
		}

		//8个S-盒
		for (j = 0, k = 0, m = 0; j < 8; ++j, k += 6) {
			//根据S-盒映射规则计算数组偏移量
			mapS = ((ERn[k] << 1) + ERn[k + 5]) << 4;
			mapS += (ERn[k + 1] << 3) + (ERn[k + 2] << 2) + (ERn[k + 3] << 1) + ERn[k + 4];
			//找到S-盒对应数值
			tS = Sn[j][mapS];
			//数值转换为4个bit位
			ERn[m++] = tS >> 3;
			ERn[m++] = tS >> 2 & 0x01;
			ERn[m++] = tS >> 1 & 0x01;
			ERn[m++] = tS & 0x01;
		}

		for (j = 0; j < 32; ++j) {
			//f函数内的P置换
			pRn[j] = ERn[P[j]];
			//结果和Ln异或
			pRn[j] = pRn[j] ^ Ln[j];
		}

		//交换Ln和Rn
		memcpy(darr64, Rn, 32);
		memcpy((unsigned char*)(&darr64) + 32, pRn, 32);
	}

	//最后再次交换一次Ln和Rn
	memcpy((unsigned char*)(&darr64) + 32, darr64, 32);
	memcpy(darr64, pRn, 32);

	//逆初始置换IP-1
	for (i = 0; i < 64; ++i) {
		bdata[i] = darr64[IP_M1[i]];
	}

	//数组合成byte
	bytes2bits(ciphertext, bdata, 64);

	return 0;

fail:
	return -1;
}

//des解密,ciphertext为密文——8bytes,key为密钥——8bytes,data为输出明文——8bytes
int des_decrypt(unsigned char* ciphertext, unsigned char* key, unsigned char* data) {
	long int i, j, k, m;
	unsigned char bcipher[64];
	unsigned char bkey[64];
	unsigned char carr64[64];
	unsigned char* Ln;
	unsigned char* Rn;
	unsigned char ERn[48];
	unsigned char pRn[32];

	unsigned char karr[56];
	unsigned char Cn[56];
	unsigned char Dn[56];
	unsigned char* pfCn = (unsigned char*)(&Cn) + 28;
	unsigned char* pfDn = (unsigned char*)(&Dn) + 28;
	unsigned char tCnDn[56];
	unsigned char kn[48];
	unsigned char tS;

	short int mapS;

	if (ciphertext == NULL || key == NULL || data == NULL) {
		goto fail;
	}

	//先将密文和密钥拆分每个bit位到数组中
	bits2bytes(bcipher, ciphertext, 64);
	bits2bytes(bkey, key, 64);

	//初始IP置换
	for (i = 0; i < 64; ++i) {
		carr64[i] = bcipher[IP[i]];
	}

	//划分Ln和Rn
	Ln = carr64;
	Rn = carr64 + 32;

	//密钥初始置换
	for (i = 0; i < 56; ++i) {
		karr[i] = bkey[PC_1[i]];
	}

	//将初始替换后的密钥分为左半部分和右半部分,分别复制两遍到另一个数组中,这样有利于移位
	memcpy(Cn, karr, 28);
	memcpy((unsigned char*)(&Cn) + 28, karr, 28);
	memcpy(Dn, (unsigned char*)(&karr) + 28, 28);
	memcpy((unsigned char*)(&Dn) + 28, (unsigned char*)(&karr) + 28, 28);

	//16次轮解密
	for (i = 0; i < 16; ++i) {
		//调整指针位置,实际上实现的就是密钥编排中的移位
		pfCn -= RSn[i];
		pfDn -= RSn[i];

		//调整完成后重新组一个数组
		memcpy(tCnDn, pfCn, 28);
		memcpy((unsigned char*)(&tCnDn) + 28, pfDn, 28);

		for (j = 0; j < 48; ++j) {
			//密钥编排中的PC-2置换
			kn[j] = tCnDn[PC_2[j]];
			//同时实现拓展置换E
			ERn[j] = Rn[E[j]];
			//轮密钥和拓展置换后结果进行异或
			ERn[j] = ERn[j] ^ kn[j];
		}

		//8个S-盒
		for (j = 0, k = 0, m = 0; j < 8; ++j, k += 6) {
			//根据S-盒映射规则计算数组偏移量
			mapS = ((ERn[k] << 1) + ERn[k + 5]) << 4;
			mapS += (ERn[k + 1] << 3) + (ERn[k + 2] << 2) + (ERn[k + 3] << 1) + ERn[k + 4];
			//找到S-盒对应数值
			tS = Sn[j][mapS];
			//数值转换为4个bit位
			ERn[m++] = tS >> 3;
			ERn[m++] = tS >> 2 & 0x01;
			ERn[m++] = tS >> 1 & 0x01;
			ERn[m++] = tS & 0x01;
		}

		for (j = 0; j < 32; ++j) {
			//f函数内的P置换
			pRn[j] = ERn[P[j]];
			//结果和Ln异或
			pRn[j] = pRn[j] ^ Ln[j];
		}

		//交换Ln和Rn
		memcpy(carr64, Rn, 32);
		memcpy((unsigned char*)(&carr64) + 32, pRn, 32);
	}

	//最后再次交换一次Ln和Rn
	memcpy((unsigned char*)(&carr64) + 32, carr64, 32);
	memcpy(carr64, pRn, 32);

	//逆初始置换IP-1
	for (i = 0; i < 64; ++i) {
		bcipher[i] = carr64[IP_M1[i]];
	}

	//数组合成byte
	bytes2bits(data, bcipher, 64);

	return 0;

fail:
	return -1;
}

int main() {
	unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
	unsigned char key[] = { 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
	unsigned char cipher[8] = { 0 };
	unsigned char plaintext[8] = { 0 };
	int i;

	des_encrypt(data, key, cipher);

	for (i = 0; i < 8; ++i) {
		printf("%#x ", cipher[i]);
	}
	printf("\n");

	des_decrypt(cipher, key, plaintext);

	for (i = 0; i < 8; ++i) {
		printf("%#x ", plaintext[i]);
	}
	printf("\n");

	return 0;
}

在MSVC2022环境下编译无问题。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值