Bootstrap

国密之OpenSSL库的SM4对称加密应用说明

一、OpenSSL简介

​ 在计算机网络上,OpenSSL是一个开放源代码的[软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。

SSLSecure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准。

1、官网网址

地址:https://www.openssl.org

在这里插入图片描述

2、GitHub地址

地址:https://github.com/openssl/openssl

在这里插入图片描述

二、SM4简介

SM4(国密算法)是由中国国家密码管理局(State Cryptography AdministrationSCA)提出的分组密码算法,是一种对称加密算法。它是中国国家商用密码算法,也是 ISO/IEC 标准(ISO/IEC 18033-3:2010)中的一部分。SM4 算法被广泛用于中国国内的商用加密应用中。

1、SM4特点

  • 分组密码: SM4 是一种分组密码,它将明文和密钥按照固定长度的分组进行加密和解密。
  • 分组长度: 分组长度为 128 位(16 字节)。
  • 密钥长度: 支持密钥长度为 128 位(16 字节)。
  • 加密模式: SM4 支持 ECBElectronic Codebook)模式,这是一种基本的分组密码加密模式。
  • 代替和置换网络(Substitution-Permutation Network,SPN)结构: SM4 算法采用 SPN 结构,包括多轮的代替(Substitution)和置换(Permutation)操作,以增加加密的难度和安全性。
  • 非线性和线性运算: SM4算法中的代替操作(S-Box 替代)是非线性的,而置换操作是线性的,这种结合增加了算法的安全性。

2、SM4安全性

SM4 算法的设计目标是提供高度的安全性,抵抗各种已知的攻击。它经过了广泛的密码学分析和测试,并且已经被国际上的密码学专家接受。

3、SM4使用场景

SM4 算法主要用于商用加密领域,例如金融领域的安全支付、电子身份认证、电子票据等。

SM4 算法的具体细节和设计原理可以在国家密码管理局的官方文档中找到。请注意,SM4 算法是受到专利保护的,使用 SM4 算法需要遵循相关的法律法规和标准。

4、加密模式

  • ECB(Electronic Codebook)模式:ECB 模式将明文分成固定大小的块,然后每个块单独加密,加密后的块串联起来形成密文。在 ECB 模式下,相同的明文块会被加密成相同的密文块,因此 ECB 模式不提供重放攻击的保护,而且不适用于对长文本的加密,因为长文本可能会有相同的块,导致相同的密文块
  • CBC 模式(Cipher Block Chaining):CBC 模式中,每个明文块在加密之前会与前一个密文块进行异或运算。这样可以使相同的明文块在加密时得到不同的密文块,增加了安全性。
  • CFB 模式(Cipher Feedback): CFB 模式中,密文块被反馈到加密算法的输入,然后再与明文进行异或运算,生成密文。CFB 模式可以实现分位加密,适用于流数据的加密。
  • OFB 模式(Output Feedback): OFB 模式中,密文块被反馈到加密算法的输入,生成一个密钥流(keystream),然后将密钥流与明文进行异或运算,生成密文。OFB 模式可以实现分位加密,且具有自同步性质。
  • CTR 模式(Counter): CTR 模式中,每个明文块都与一个唯一的计数器值进行加密,计数器的值可以是明文块的块序号。CTR 模式不需要反馈,可以并行加密,适用于高速加密需求。

三、获取预编译版OpenSSL

1、下载

如果自己编译OpenSSL 比较麻烦,则可以下载预先编译好的OpenSSL 库。地址如下:

https://slproweb.com/products/Win32OpenSSL.html

在这里插入图片描述

点击下载对应版本 MSI 即可。

在这里插入图片描述

下载后如下:

在这里插入图片描述

2、安装

直接双击安装即可。

在这里插入图片描述

安装后目录结构如下:
在这里插入图片描述

四、OpenSSL+VS2019+SM4加解密

1、C++代码

#include <iostream>
#include <string>
#include <chrono>

#include <openssl/evp.h>
#include <openssl/rand.h>


std::string strKey = "a56egSpSWd5e67c3";

// 加密函数
void SM4Encrypt(const unsigned char* plaintext, int plaintextLength, const unsigned char* key, unsigned char* ciphertext, int* ciphertextLength)
{
	EVP_CIPHER_CTX* ctx;
	int len;

	// 创建并初始化上下文
	ctx = EVP_CIPHER_CTX_new();
	EVP_EncryptInit_ex(ctx, EVP_sm4_ecb(), NULL, key, NULL);

	// 加密数据
	EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintextLength);
	*ciphertextLength = len;

	// 结束加密过程
	EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
	*ciphertextLength += len;

	// 释放上下文
	EVP_CIPHER_CTX_free(ctx);
}

// 解密函数
void SM4Decrypt(const unsigned char* ciphertext, int ciphertextLength, const unsigned char* key, unsigned char* plaintext, int* plaintextLength)
{
	EVP_CIPHER_CTX* ctx;
	int len;

	// 创建并初始化上下文
	ctx = EVP_CIPHER_CTX_new();
	EVP_DecryptInit_ex(ctx, EVP_sm4_ecb(), NULL, key, NULL);

	// 解密数据
	EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertextLength);
	*plaintextLength = len;

	// 结束解密过程
	EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
	*plaintextLength += len;

	// 释放上下文
	EVP_CIPHER_CTX_free(ctx);
}

int main()
{
	char buff[4096];

	FILE* fp = fopen("testxml.xml", "rt");
	if (fp)
	{
		std::string strRaw;
		while (fgets(buff,sizeof(buff),fp))
		{
			strRaw += std::string(buff);
		}
		printf("【原始串《长度=%d》】=%s.\n",strRaw.length(), strRaw.c_str());

		auto start = std::chrono::steady_clock::now();
		
		 // 加密
		unsigned char ciphertext[50280];  
		int ciphertextLength = 0;
		SM4Encrypt((unsigned char*)strRaw.c_str(), strRaw.length() - 1, (unsigned char*)strKey.c_str(), ciphertext, &ciphertextLength);
		
		printf("\n【加密串】= ");
		for (int i = 0; i < ciphertextLength; ++i)
		{
			printf("%02X", ciphertext[i]);
		}
		printf("\n");
		
		auto end = std::chrono::steady_clock::now();
		// 计算时间间隔
		std::chrono::duration<double> duration =
			std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
		// 输出时间间隔
		std::cout << "耗时: " << duration.count() << " seconds\n";
	}

	return 0;
}

2、头文件包含

在这里插入图片描述

3、库目录包含

在这里插入图片描述

添加 "libcrypto.lib" "libssl.lib" 文件。
在这里插入图片描述

4、运行效果

在这里插入图片描述

五、OpenSSL+VC6.0+SM4加解密

1、代码适配

Visual Studio的代码移植到 VC6.0 时,会报错。解决方法如下:

①、修改openssl/macros.h文件:

注释箭头指向的 "__declspec(restrict)" 内容:
在这里插入图片描述

②、修改openssl/bio.h文件:

VC6.0 没有 "uintptr_t" ,需要增加 "typedef unsigned int uintptr_t" ,如第一个箭头指向处:

在这里插入图片描述

;