C/C++教程

国密SM4的C51源码C语言8051(ECB、CBC)

本文主要是介绍国密SM4的C51源码C语言8051(ECB、CBC),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、概述

SM4是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”

SM4主要用于数据加密,为非对称加密,其算法公开,分组长度与密钥长度均为128bit,加密算法与密钥扩展算法都采用32轮非线性迭代结构,S盒为固定的8比特输入8比特输出。

SM4无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

sm4非常节省资源,8051完全没有问题!

 

完整源码下载地址 :https://download.csdn.net/download/guoggn/18548821

二、流程

1、非线性变换t

      查表Sbox替换

2、线性变换L

     循环左移

3、32次轮迭代交换

4、反序变换

三、秘钥扩展

  秘钥128位扩展为256字节,方法同加密类似。

   

四、ECB和CBC

ECB(Electronic Code Book)/电码本模式,16字节一分组,组和组之间没有关系,组内容相同加密结果相同。

CBC(Cipher Block Chaining)/密文分组链接方式,首组用到IV,后一组用到前一组的输出,内容相同的组加密结果不同。

五、代码

/*
* sm4.c
* 此算法适用于C51的8位机
* C51为大端模式
* 输入数据长度不限,必须是16字节的倍数。
* 若是16字节倍数,需要先补齐到16字节倍数,
* SM3对输入数据分块取HASH,每消息块长度最大限定为64字节,
*/

// SMS4的密钥扩展算法
// 参数说明:Key为加密密钥,rk为扩展后密钥
void SMS4KeyExt(u8 *key, u32 *rk)
{
	int i = 0; 
	u32 k[36] = { 0 };     //用于密钥扩展算法与系统参数FK运算后的结果存储
	u32 *pMK = (u32 *)key;	//加密秘钥
	
#ifdef _DEBUG
	printf("pMK = \n");
	for (i = 0; i < 4; i++)
		printf("%l08x, ", pMK[i]);
	printf("\n\n");
#endif

	k[0] = pMK[0] ^ FK[0];
	k[1] = pMK[1] ^ FK[1];
	k[2] = pMK[2] ^ FK[2];
	k[3] = pMK[3] ^ FK[3];
	
#ifdef _DEBUG
	printf("k = \n");
	for (i = 0; i < 32; i++)
		printf("%l08x, ", k[i]);
	printf("\n\n");
#endif

	//32次循环迭代运算
	for (i = 0; i < 32; i++)
	{
		k[i + 4] = k[i] ^ T_key(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]);
		rk[i] = k[i + 4];
	}

#ifdef _DEBUG
	printf("rk = \n");
	for (i = 0; i < 32; i++)
		printf("%l08x, ", rk[i]);
	printf("\n\n");
#endif
}
	
	
//len:数据长度(16字节倍数) key:密钥(16字节) input:输入的原始数据 output:加密后输出数据
void SM4_CBC_EnCrypt(u8 *iv, u8 *key, u8 *input, u8 *output, u8 len)
{
	int i = 0, j = 0; 
	u32 rk[32] = { 0 };    //轮秘钥
	u32 x[36] = { 0 };     //用于存放输入的32轮加解密过程数据
	u32 *pIV = (u32 *)iv;	//IV输入
	u32 *pX = (u32 *)input;	//明文输入	
	u32 *pY = (u32 *)output;	//明文输入
	
	if((len%16 != 0) || (len  == 0))
	{
			printf("LEN ERRORR!!!\r\n");
			return ;
	}
	
	//密钥扩展
	SMS4KeyExt(key,rk);
	
	//16字节分组加密
	for (j = 0; j < (len/16); j++)
	{
		if(j == 0)
		{
			x[0] = pX[4*j+0] ^ pIV[0];
			x[1] = pX[4*j+1] ^ pIV[1];
			x[2] = pX[4*j+2] ^ pIV[2];
			x[3] = pX[4*j+3] ^ pIV[3];
		}
		else
		{
		
			x[0] = pX[4*j+0] ^ pY[4*(j-1)+0];
			x[1] = pX[4*j+1] ^ pY[4*(j-1)+1];
			x[2] = pX[4*j+2] ^ pY[4*(j-1)+2];
			x[3] = pX[4*j+3] ^ pY[4*(j-1)+3];
		}
		
		//32次迭代运算
		for (i = 0; i < 32; i++)
		{
			x[i + 4] = x[i] ^ T_data(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ rk[i]);
		}
		
		#ifdef _DEBUG
			printf("x[4] = \n");
			for (i = 4; i < 36; i++)
				printf("%l08x, ", x[i]);
			printf("\n\n");
		#endif
		
		//反序变换
		pY[4*j+0] = x[35];
		pY[4*j+1] = x[34];
		pY[4*j+2] = x[33];
		pY[4*j+3] = x[32];
	}
	
#ifdef _DEBUG
	printf("pY = \n");
	for (i = 0; i < 4; i++)
		printf("%l08x, ", pY[i]);
	printf("\n\n");
#endif
}

 

int sm4test(void)
{
	u8 i,len;
	u8 encode_Result[64] = { 0 };    //定义加密输出缓存区
	u8 decode_Result[64] = { 0 };    //定义解密输出缓存区
	       //定义16字节的IV
	u8 iv[16] = { 0 };
	       //定义16字节的密钥
	u8 key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
				//定义64字节的原始输入数据(测试用)
	u8 Data_plaintext[64] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, \
														0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, \
														0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, \
														0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };

	//len = 16;
	len = 64;

	//ECB数据加密
	printf("enc in:\n");
	for (i = 0; i < len ; i++)
		printf("%b02x ", *(Data_plaintext + i));
	printf("\n\n");
		
	SM4_ECB_Crypt(ENCRYPT, key, Data_plaintext, encode_Result, len);
	printf("enc out:\n");
	for (i = 0; i < len ; i++)
		printf("%b02x ", *(encode_Result + i));
	printf("\n\n");
	//681EDF34D206965E86B3E94F536E4246681EDF34D206965E86B3E94F536E4246681EDF34D206965E86B3E94F536E4246681EDF34D206965E86B3E94F536E4246

	//ECB数据解密
	SM4_ECB_Crypt(DECRYPT, key, encode_Result, decode_Result, len);
	printf("dec out:\n");
	for (i = 0; i < len; i++)
		printf("%b02x ", *(decode_Result + i));
	printf("\n\n");
	
		//CBC数据加密
	printf("CBC enc in:\n");
	for (i = 0; i < len ; i++)
		printf("%b02x ", *(Data_plaintext + i));
	printf("\n\n");
		
	SM4_CBC_EnCrypt(iv, key, Data_plaintext, encode_Result, len);
	printf("CBC enc out:\n");
	for (i = 0; i < len ; i++)
		printf("%b02x ", *(encode_Result + i));
	printf("\n\n");
	//681EDF34D206965E86B3E94F536E42469FF11DCFD3AFAA236C76090BABC3BB85B0F13BEFF6EDE1BBEB43705EE30AAD990D5A28DAFD1ABE1521DD7E247E0249C0

	//CBC数据解密
	SM4_CBC_DeCrypt(iv, key, encode_Result, decode_Result, len);
	printf("CBC dec out:\n");
	for (i = 0; i < len; i++)
		printf("%b02x ", *(decode_Result + i));
	printf("\n\n");
	
	
	
	return 0;
}

 

 

 

参考:

https://blog.csdn.net/weixin_42700740/article/details/102667012?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

https://blog.csdn.net/weixin_37569048/article/details/94983841

https://blog.csdn.net/sinolover/article/details/112307366?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162061071816780357224251%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162061071816780357224251&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-5-112307366.first_rank_v2_pc_rank_v29&utm_term=sm4+cbc&spm=1018.2226.3001.4187

这篇关于国密SM4的C51源码C语言8051(ECB、CBC)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!