SM4算法的C++实现(代码)

一、SM4算法简介

  1. SM4算法是一个分组算法,分组长度为128比特,密钥长度为128比特。
  2. SM4算法的加密算法和密钥扩展算法都采用了32轮非线性迭代结构。
  3. SM4算法的解密算法和加密算法的结构相同,除了轮密钥的使用顺序是加密轮密钥的逆序。
  4. SM4算法的加密流程图大致如下图所示。
    在这里插入图片描述

二、SM4算法的C++实现

1.C++代码

#include <iostream>
#include <string>
#include <cmath>
using namespace std;

string BinToHex(string str) {//二进制转换为十六进制的函数实现
	string hex = "";
	int temp = 0;
	while (str.size() % 4 != 0) {
		str = "0" + str;
	}
	for (int i = 0; i < str.size(); i += 4) {
		temp = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + (str[i + 3] - '0') * 1;
		if (temp < 10) {
			hex += to_string(temp);
		}
		else {
			hex += 'A' + (temp - 10);
		}
	}
	return hex;
}

string HexToBin(string str) {//十六进制转换为二进制的函数实现
	string bin = "";
	string table[16] = { "0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };
	for (int i = 0; i < str.size(); i++) {
		if (str[i] >= 'A'&&str[i] <= 'F') {
			bin += table[str[i] - 'A' + 10];
		}
		else {
			bin += table[str[i] - '0'];
		}
	}
	return bin;
}


int HexToDec(char str) {//十六进制转换为十进制的函数实现
	int dec = 0;
	if (str >= 'A' && str <= 'F') {
		dec += (str - 'A' + 10);
	}
	else {
		dec += (str - '0');
	}
	return dec;
}

string LeftShift(string str, int len) {//循环左移len位函数实现
	string res = HexToBin(str);
	res = res.substr(len) + res.substr(0, len);
	return BinToHex(res);
}

string XOR(string str1, string str2) {//异或函数实现
	string res1 = HexToBin(str1);
	string res2 = HexToBin(str2);
	string res = "";
	for (int i = 0; i < res1.size(); i++) {
		if (res1[i] == res2[i]) {
			res += "0";
		}
		else {
			res += "1";
		}
	}
	return BinToHex(res);
}

string NLTransform(string str) {//非线性变换t函数实现
	string Sbox[16][16] = { {"D6","90","E9","FE","CC","E1","3D","B7","16","B6","14","C2","28","FB","2C","05"},
						 {"2B","67","9A","76","2A","BE","04","C3","AA","44","13","26","49","86","06","99"},
						 {"9C","42","50","F4","91","EF","98","7A","33","54","0B","43","ED","CF","AC","62"},
						 {"E4","B3","1C","A9","C9","08","E8","95","80","DF","94","FA","75","8F","3F","A6"},
						 {"47","07","A7","FC","F3","73","17","BA","83","59","3C","19","E6","85","4F","A8"},
						 {"68","6B","81","B2","71","64","DA","8B","F8","EB","0F","4B","70","56","9D","35"},
						 {"1E","24","0E","5E","63","58","D1","A2","25","22","7C","3B","01","21","78","87"},
						 {"D4","00","46","57","9F","D3","27","52","4C","36","02","E7","A0","C4","C8","9E"},
						 {"EA","BF","8A","D2","40","C7","38","B5","A3","F7","F2","CE","F9","61","15","A1"},
						 {"E0","AE","5D","A4","9B","34","1A","55","AD","93","32","30","F5","8C","B1","E3"},
						 {"1D","F6","E2","2E","82","66","CA","60","C0","29","23","AB","0D","53","4E","6F"},
						 {"D5","DB","37","45","DE","FD","8E","2F","03","FF","6A","72","6D","6C","5B","51"},
						 {"8D","1B","AF","92","BB","DD","BC","7F","11","D9","5C","41","1F","10","5A","D8"},
						 {"0A","C1","31","88","A5","CD","7B","BD","2D","74","D0","12","B8","E5","B4","B0"},
						 {"89","69","97","4A","0C","96","77","7E","65","B9","F1","09","C5","6E","C6","84"},
						 {"18","F0","7D","EC","3A","DC","4D","20","79","EE","5F","3E","D7","CB","39","48"} };
	string res = "";
	for (int i = 0; i < 4; i++) {
		res = res + Sbox[HexToDec(str[2 * i])][HexToDec(str[2 * i + 1])];
	}
	return res;
}

string LTransform(string str) {//线性变换L函数实现
	return XOR(XOR(XOR(XOR(str, LeftShift(str, 2)), LeftShift(str, 10)), LeftShift(str, 18)), LeftShift(str, 24));
}

string L2Transform(string str) {//线性变换L'函数实现
	return XOR(XOR(str, LeftShift(str, 13)), LeftShift(str, 23));
}

string T(string str) {//用于加解密算法中的合成置换T函数实现
	return LTransform(NLTransform(str));
}

string T2(string str) {//用于密钥扩展算法中的合成置换T函数实现
	return L2Transform(NLTransform(str));
}

string KeyExtension(string MK) {//密钥扩展函数实现
	string FK[4] = { "A3B1BAC6", "56AA3350", "677D9197", "B27022DC" };
	string CK[32] = { "00070E15", "1C232A31", "383F464D", "545B6269",
				      "70777E85", "8C939AA1", "A8AFB6BD", "C4CBD2D9",
				      "E0E7EEF5", "FC030A11", "181F262D", "343B4249",
				      "50575E65", "6C737A81", "888F969D", "A4ABB2B9",
				      "C0C7CED5", "DCE3EAF1", "F8FF060D", "141B2229",
				      "30373E45", "4C535A61", "686F767D", "848B9299",
				      "A0A7AEB5", "BCC3CAD1", "D8DFE6ED", "F4FB0209",
				      "10171E25", "2C333A41", "484F565D", "646B7279" };
	string K[36] = { XOR(MK.substr(0,8),FK[0]),XOR(MK.substr(8,8),FK[1]),XOR(MK.substr(16,8),FK[2]),XOR(MK.substr(24),FK[3]) };
	string rks = "";
	for (int i = 0; i < 32; i++) {
		K[i + 4] = XOR(K[i], T2(XOR(XOR(XOR(K[i + 1], K[i + 2]), K[i + 3]), CK[i])));
		rks += K[i + 4];
	}
	return rks;
}

string encode(string plain, string key) {//加密函数实现
	cout << "轮密钥与每轮输出状态:" << endl;
	cout << endl;
	string cipher[36] = { plain.substr(0,8),plain.substr(8,8),plain.substr(16,8),plain.substr(24) };
	string rks = KeyExtension(key);
	for (int i = 0; i < 32; i++) {
		cipher[i + 4] = XOR(cipher[i], T(XOR(XOR(XOR(cipher[i + 1], cipher[i + 2]), cipher[i + 3]), rks.substr(8 * i, 8))));
		cout << "rk[" + to_string(i) + "] = " + rks.substr(8 * i, 8) + "    X[" + to_string(i) + "] = " + cipher[i + 4] << endl;
	}
	cout << endl;
	return cipher[35] + cipher[34] + cipher[33] + cipher[32];
}

string decode(string cipher, string key) {//解密函数实现
	cout << "轮密钥与每轮输出状态:" << endl;
	cout << endl;
	string plain[36] = { cipher.substr(0,8),cipher.substr(8,8), cipher.substr(16,8), cipher.substr(24,8) };
	string rks = KeyExtension(key);
	for (int i = 0; i < 32; i++) {
		plain[i + 4] = XOR(plain[i], T(XOR(XOR(XOR(plain[i + 1], plain[i + 2]), plain[i + 3]), rks.substr(8 * (31 - i), 8))));
		cout << "rk[" + to_string(i) + "] = " + rks.substr(8 * (31 - i), 8) + "    X[" + to_string(i) + "] = " + plain[i + 4] << endl;
	}
	cout << endl;
	return plain[35] + plain[34] + plain[33] + plain[32];
}

int main() {//主函数
	string str = "0123456789ABCDEFFEDCBA9876543210";
	cout << "明    文:" << str.substr(0, 8) << "  " << str.substr(8, 8) << "  " << str.substr(16, 8) << "  " << str.substr(24, 8) << endl;
	cout << endl;
	string key = "0123456789ABCDEFFEDCBA9876543210";
	cout << "加密密钥:" << key.substr(0, 8) << "  " << key.substr(8, 8) << "  " << key.substr(16, 8) << "  " << key.substr(24, 8) << endl;
	cout << endl;
	string cipher = encode(str, key);
	cout << "密    文:" << cipher.substr(0, 8) << "  " << cipher.substr(8, 8) << "  " << cipher.substr(16, 8) << "  " << cipher.substr(24, 8) << endl;
	cout << endl;
	cout << "密    文:" << cipher.substr(0, 8) << "  " << cipher.substr(8, 8) << "  " << cipher.substr(16, 8) << "  " << cipher.substr(24, 8) << endl;
	cout << endl;
	cout << "解密密钥:" << key.substr(0, 8) << "  " << key.substr(8, 8) << "  " << key.substr(16, 8) << "  " << key.substr(24, 8) << endl;
	cout << endl;
	string plain = decode(cipher, key);
	cout << "明    文:" << plain.substr(0, 8) << "  " << plain.substr(8, 8) << "  " << plain.substr(16, 8) << "  " << plain.substr(24, 8) << endl;
}

2.运行结果

  1. 加密运算运行结果图:
    在这里插入图片描述

  2. 解密运算运行结果图:
    在这里插入图片描述

  • 12
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
在C语言中使用SM2算法,需要使用相应的SM2算法库。以下是使用OpenSSL库实现SM2算法的步骤: 1. 安装OpenSSL库:在Linux系统中使用命令`sudo apt-get install openssl`安装OpenSSL库,或者从OpenSSL官网下载源码进行编译安装。 2. 生成密钥对:使用OpenSSL库中的命令行工具`openssl`生成SM2密钥对,并将公钥和私钥保存到文件中,例如: ``` openssl ecparam -name sm2p256v1 -genkey -out sm2_key.pem ``` 3. 加密:使用OpenSSL库中的函数`EVP_PKEY_encrypt()`对明文进行SM2加密。首先读取公钥文件,并将明文数据读入缓冲区,然后调用`EVP_PKEY_encrypt()`函数进行加密,例如: ``` FILE* fp = fopen("sm2_key.pem", "r"); EVP_PKEY* pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); fclose(fp); unsigned char plaintext[1024] = "Hello, SM2!"; int plaintext_len = strlen((char*)plaintext); unsigned char ciphertext[1024]; int ciphertext_len = EVP_PKEY_encrypt(ciphertext, plaintext_len, plaintext, plaintext_len, pkey); ``` 4. 解密:使用OpenSSL库中的函数`EVP_PKEY_decrypt()`对密文进行SM2解密。首先读取私钥文件,并将密文数据读入缓冲区,然后调用`EVP_PKEY_decrypt()`函数进行解密,例如: ``` FILE* fp = fopen("sm2_key.pem", "r"); EVP_PKEY* pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); fclose(fp); unsigned char ciphertext[1024] = {0x02, 0xa6, 0x55, 0x9c, 0x4f, 0x1c, 0x31, 0x02, 0x0c, 0x69, 0x4c, 0x68, 0x4f, 0x2d, 0x6d, 0x2a, 0x8d, 0x52, 0x6e, 0x5f, 0x70, 0x5f, 0x57, 0x1f, 0x0f, 0x7d, 0x96, 0xb1, 0x88, 0x8d, 0x7f, 0x89, 0x56, 0x38, 0x7a, 0xb2, 0x5f, 0xcc, 0x9c, 0x7c, 0x1f, 0x5e, 0xc8, 0x7b, 0xa7, 0x39, 0x1e, 0x71, 0x4c, 0x08, 0x2f, 0x37, 0x3a, 0x1b, 0x48, 0x8f, 0x50, 0x5c, 0x5c}; int ciphertext_len = 53; unsigned char plaintext[1024]; int plaintext_len = EVP_PKEY_decrypt(plaintext, ciphertext_len, ciphertext, ciphertext_len, pkey); ``` 5. 签名:使用OpenSSL库中的函数`EVP_DigestSign()`对消息进行SM2签名。首先读取私钥文件,并将消息数据读入缓冲区,然后调用`EVP_DigestSign()`函数进行签名,例如: ``` FILE* fp = fopen("sm2_key.pem", "r"); EVP_PKEY* pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); fclose(fp); unsigned char message[1024] = "Hello, SM2!"; int message_len = strlen((char*)message); EVP_MD_CTX* ctx = EVP_MD_CTX_new(); EVP_DigestSignInit(ctx, NULL, EVP_sm3(), NULL, pkey); EVP_DigestSignUpdate(ctx, message, message_len); unsigned char signature[1024]; size_t signature_len; EVP_DigestSignFinal(ctx, NULL, &signature_len); EVP_DigestSignFinal(ctx, signature, &signature_len); EVP_MD_CTX_free(ctx); ``` 6. 验签:使用OpenSSL库中的函数`EVP_DigestVerify()`对签名进行SM2验签。首先读取公钥文件,并将消息数据和签名数据读入缓冲区,然后调用`EVP_DigestVerify()`函数进行验签,例如: ``` FILE* fp = fopen("sm2_key.pem", "r"); EVP_PKEY* pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); fclose(fp); unsigned char message[1024] = "Hello, SM2!"; int message_len = strlen((char*)message); unsigned char signature[1024] = {0x30, 0x44, 0x02, 0x20, 0x19, 0x1f, 0x21, 0xb3, 0xe5, 0x72, 0x9d, 0x3e, 0x06, 0x4f, 0x69, 0xb8, 0x3a, 0x90, 0x8f, 0x96, 0x2a, 0x2e, 0x09, 0x8e, 0x3d, 0xe1, 0x34, 0xd8, 0xfa, 0x20, 0x8f, 0x0d, 0x5e, 0x7b, 0x02, 0x20, 0x2a, 0x4f, 0xd4, 0x6b, 0x6d, 0xf0, 0x06, 0x3b, 0x5e, 0x5b, 0x90, 0x18, 0x6d, 0x89, 0x0f, 0x8e, 0x6a, 0x3b, 0x2e, 0x74, 0x98, 0x8b, 0xdc, 0x97, 0x30, 0x51, 0x1a, 0x84, 0x3e, 0x00, 0x7e, 0x33}; int signature_len = 72; EVP_MD_CTX* ctx = EVP_MD_CTX_new(); EVP_DigestVerifyInit(ctx, NULL, EVP_sm3(), NULL, pkey); EVP_DigestVerifyUpdate(ctx, message, message_len); int ret = EVP_DigestVerifyFinal(ctx, signature, signature_len); EVP_MD_CTX_free(ctx); if (ret == 1) { printf("signature valid\n"); } else { printf("signature invalid\n"); } ``` 以上是使用OpenSSL库实现SM2算法的基本步骤,需要注意的是,SM2算法的具体实现还需要考虑数据格式、填充方式、密钥管理等方面的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值