一、概述
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