【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)

文章目录

  • 1、简介
  • 2、下载openssl
    • 2.1 下载openssl源码(github)
    • 2.2 下载openssl源码(官网压缩包)
    • 2.3 下载openssl二进制库
    • 2.4 下载perl工具
  • 3、编译openssl
    • 3.1 Perl
    • 3.2 Microsoft Visual C 编译器
    • 3.3 快速开始
  • 4、使用openssl(C++)
    • 4.1 配置开发环境
    • 4.2 MD5实现
    • 4.3 SHA256实现
  • 5、使用openssl(命令行openssl.exe)
    • 5.1 私钥公钥生成
    • 5.2 自签名证书生成
    • 5.3 加密文件
  • 6、使用openssl(python)
  • 7、个人测试
    • 7.1 软件License许可证文件实现(C++)
    • 7.2 批量加密图片文件(python)
    • 7.3 图片Arnold置乱算法(python)
  • 结语

1、简介

OpenSSL 是用于传输层安全 (TLS) 协议(以前称为安全套接字层 (SSL) 协议)的强大、商业级、功能齐全的开源工具包。协议实现基于全强度通用密码库,也可以单独使用。

  • OpenSSL 源自 Eric A. Young 和 Tim J. Hudson 开发的 SSLeay 库。
  • OpenSSL 项目的官方主页是www.openssl.org。
  • OpenSSL(密码学和 SSL/TLS 工具包) 项目开发和维护 OpenSSL 软件——一个强大的、商业级的、功能齐全的工具包,用于通用加密和安全通信。
  • OpenSSL采用C语言作为开发语言,这使得OpenSSL具有优秀的跨平台性能。OpenSSL支持Linux、Windows、BSD、Mac、VMS等平台,这使得OpenSSL具有广泛的适用性。

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第1张图片
SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准。

OpenSSL 工具包包括:

  • libssl: TLSv1.3 ( RFC 8446 ) 之前的所有 TLS 协议版本的实现。

  • libcrypto: 一个全强度的通用加密库。它构成了 TLS 实现的基础,但也可以独立使用。

  • openssl: OpenSSL 命令行工具,用于加密任务、测试和分析的瑞士军刀。它可用于
    创建关键参数
    创建 X.509 证书、CSR 和 CRL
    消息摘要的计算
    加密和解密
    SSL/TLS 客户端和服务器测试
    处理 S/MIME 签名或加密邮件
    和更多…

  • 公钥和私钥:
    非对称加密是用密钥对数据进行加密,然后我们可以使用另一个不同的密钥对数据进行解密。这两个密钥就是公钥和私钥。
    每个用户都有一对公钥和私钥,私钥和公钥都拥有加密和解密功能。其中私钥可以进行签名,公钥可以进行验签。
    私钥用来进行解密和签名,是给自己用的。
    公钥由本人公开,用于加密和验证签名,是给别人用的。
    当该用户发送文件时,用私钥签名,别人用他给的公钥解密,可以保证该信息是由他发送的。即数字签名。
    当该用户接受文件时,别人用他的公钥加密,他用私钥解密,可以保证该信息只能由他接收到。可以避免被其他人看到。
    我们根据私钥可以计算出公钥,但是我们根据公钥计算不出来私钥的。私钥一般是有服务器掌握的,公钥则是在客户端使用的。

  • 数字签名:
    它会将报文使用一定的HASH算法算出一个固定位数的摘要信息,然后使用私钥将摘要加密,然后会将刚才的报文一起发送给接收者,接收者会通过公钥将摘要解出来。也通过hash算法算出报文摘要,如果两个摘要一致,说明数据未被篡改,说明数据是完整的。

  • 数字证书:
    (1)它是由CA颁发给网站的一种身份的方式。它里面包含了该网站的公钥、有效时间、网站的地址、及 CA的数字签名等。
    (2)它是数字形式的标识。它是由证书颁发机构(CA)的权威机构颁发的,由该权威机构担保证书信息的有效性。因此数字证书只有在特定的时间段内有效。证书中包含了证书中所标识的公钥,也就是说证书里包含了你的公钥,公钥与你个人信息相匹配。
    (3)它是使用CA的私钥将网站的公钥等信息进行了签名,当客户端请求服务器端的时候,网站会把证书发给客户端,客户端先通过CA的数字签名校验CA的身份,来证明证书的真实完整性。

  • 对于常见的https证书 一般是用crt或者pem来保存。
    常见的X.509证书格式包括:

cer/crt是用于存放证书,它是2进制形式存放的,不含私钥。
pem跟crt/cer的区别是它以Ascii来表示,可以用于存放证书或私钥。
pfx/p12用于存放个人证书/私钥,他通常包含保护密码,2进制方式。
p10是证书请求。
p7r是CA对证书请求的回复,只用于导入
p7b以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥。

2、下载openssl

2.1 下载openssl源码(github)

主源代码保存在git 存储库中,可通过网络访问并在 GitHub 上进行克隆,网址为https://github.com/openssl/openssl。
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第2张图片
注意:最新的稳定版本是支持到 2026 年 9 月 7 日的 3.0 系列。这也是长期支持 (LTS) 版本。之前的 LTS 版本(1.1.1 系列)也可用,并且支持到 2023 年 9 月 11 日。所有旧版本(包括 1.1.0、1.0.2、1.0.0 和 0.9.8)现在都不再支持,应该不被使用。

  • 从原始 OpenSSL 存储库克隆它来获得:
git clone git://git.openssl.org/openssl.git
  • 或从 GitHub 镜像使用
git clone https://github.com/openssl/openssl.git

2.2 下载openssl源码(官网压缩包)

https://www.openssl.org/source/old/
直接在官网下载源码的压缩包,截图如下:

2.3 下载openssl二进制库

  • (1)https://slproweb.com/products/Win32OpenSSL.html
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第3张图片
  • (2)https://slproweb.com/products/Win32OpenSSL.html
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第4张图片

2.4 下载perl工具

  • (1)我们推荐 Strawberry Perl,可从http://strawberryperl.com/ 获得。有关更多信息,包括 CPAN 的使用,请阅读 NOTES.PERL。
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第5张图片
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第6张图片

  • (2)另一种方法是 ActiveState Perl,https /www.activestate.com/ActivePerl ,您可能需要通过https://platform.activestate.com/ActiveState显式构建 Perl 模块 Win32/Console.pm ,然后下载它。

ActiveState Perl官网截图:【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第7张图片
ActiveState Perl安装界面截图:【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第8张图片
ActiveState Perl安装之后通过命令行输出版本号:

perl -v

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第9张图片

3、编译openssl

在 Windows 平台上构建和运行 OpenSSL 有多种选择。

3.1 Perl

(1)Strawberry Perl
(2)ActiveState Perl

3.2 Microsoft Visual C 编译器

使用具有管理权限的 Visual Studio 开发人员命令提示符,根据预期的体系结构选择其变体之一。或使用选项之一运行cmd和执行, , , , , , , 或. 这会设置 , 等所需的环境变量。

另请参阅 https://docs.microsoft.com/cpp/build/building-on-the-command-linevcvarsall.batx86x86_amd64x86_armx86_arm64amd64amd64_x86amd64_armamd64_arm64nmake.execl.exe
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第10张图片

根据需要编译的平台选择相应的控制台,64位的选择x64,32位的选择x86。

如果没有找到以上菜单,可以创建命令行执行环境:
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第11张图片

  • 标题:用户自定义,会显示在TOOLS的菜单项中
  • 命令:C:\Windows\System32\cmd.exe
  • 参数:在VS2017中,配置如下:(找到vs2017安装目录)
    /k"E:\vs2017\VC\Auxiliary\Build\vcvars64.bat"(这里使用64位c/c++编译器,如果使用32位可以选vcvars32.bat)
  • 初始目录 $(ProjectDir) 此为项目目录,这是命令行启动后默认的初始目录,有几个选项。

3.3 快速开始

(1)安装 Perl
(2)安装 NASM(可选)
(3)确保 Perl 和 NASM 都在您的 %PATH% 上
(4)选择Visual Studio 开发人员命令提示符
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第12张图片
(5)从 OpenSSL 源目录的根目录输入
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第13张图片
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第14张图片
openssl官方的编译命令步骤如下:

perl Configure VC-WIN32 如果您想要 32 位 OpenSSL 或
perl Configure VC-WIN64A 如果您想要 64 位 OpenSSL 或
perl Configure VC-WIN64-ARM如果您想要 Windows on Arm (win-arm64) OpenSSL 或
perl Configure 让 Configure 找出平台
nmake
nmake test
nmake install

To build for Win64/x64:

perl Configure VC-WIN64A --prefix=c:\some\openssl\dir
ms\do_win64a
nmake -f ms\ntdll.mak
cd out32dll
…\ms\test

To build for Win64/IA64:

perl Configure VC-WIN64I --prefix=c:\some\openssl\dir
ms\do_win64i
nmake -f ms\ntdll.mak
cd out32dll
…\ms\test

To build for Win32:

perl Configure VC-WIN32 no-asm --prefix=c:/some/openssl/dir
ms\do_ms
nmake -f ms\ntdll.mak

1、如何编译unicode 版openssl?

perl Configure VC-WIN32 -DUNICODE -D_UNICODE

2、如何生成动态库和静态库?

动态库:
nmake -f ms\ntdll.mak 
静态库:
nmake -f ms\nt.mak

测试动态库:
nmake -f ms\ntdll.mak test
测试静态库:
nmake -f ms\nt.mak test

安装动态库:
nmake -f ms\ntdll.mak install
安装静态库:
nmake -f ms\nt.mak install

清除上次动态库的编译,以便重新编译:
nmake -f ms\ntdll.mak clean
清除上次静态库的编译,以便重新编译:
nmake -f ms\nt.mak clean

3、一键自动编译所有版本的命令

#64位debug静态库
perl Configure debug-VC-WIN64A no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_win64a.bat
nmake -f ms\nt.mak
nmake -f ms\nt.mak install
 
#64位release静态库
perl Configure VC-WIN64A no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_win64a.bat
nmake -f ms\nt.mak
nmake -f ms\nt.mak install
 
#64位debug动态库
perl Configure debug-VC-WIN64A no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_win64a.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
 
#64位release动态库
perl Configure VC-WIN64A no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_win64a.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
 
#32位debug静态库
perl Configure debug-VC-WIN32 no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_ms.bat
nmake -f ms\nt.mak
nmake -f ms\nt.mak install
 
#32位release静态库
perl Configure VC-WIN32 no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_ms.bat
nmake -f ms\nt.mak
nmake -f ms\nt.mak install
 
#32位debug动态库
perl Configure debug-VC-WIN32 no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_ms.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
 
#32位release动态库
perl Configure VC-WIN32 no-asm --prefix=C:\OpenSSL --openssldir=C:\SSL
ms\do_ms.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install

我们这里依次编译命令执行如下(编译64位的openssl的静态库):

perl Configure VC-WIN64A  no-asm no-shared

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第15张图片

ms\do_win64a

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第16张图片

nmake -f ms\nt.mak

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第17张图片
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第18张图片

4、使用openssl(C++)

4.1 配置开发环境

  • (1)添加openssl头文件所在文件夹
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第19张图片
  • (2)添加openssl库文件所在文件夹
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第20张图片
  • (3)添加openssl库文件
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第21张图片

4.2 MD5实现

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

std::string getMD5_1(const std::string & str)
{
	unsigned char md[MD5_DIGEST_LENGTH] = { 0 };
	MD5_CTX md5;

	MD5_Init(&md5);
	MD5_Update(&md5, str.c_str(), str.size());
	MD5_Final(md, &md5);

	char buf[MD5_DIGEST_LENGTH * 2 + 1] = { 0 };
	char tmp[3] = { 0 };
	for (auto i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf_s(tmp, "%02x", md[i]);
		strcat_s(buf, tmp);
	}

	return std::string(buf);
}

std::string getMD5_2(const std::string& str)
{
	int ret = -1;
	unsigned char md[MD5_DIGEST_LENGTH] = { 0 };
	unsigned char buf[MD5_DIGEST_LENGTH * 2 + 1] = { 0 };
	MD5_CTX c;

	//1. 初始化
	ret = MD5_Init(&c);
	if (1 != ret)
	{
		std::cout << "MD5_Init failed..." << std::endl;
		return "";
	}

	//2. 添加数据
	ret = MD5_Update(&c, (const void *)str.c_str(), str.size());
	if (1 != ret)
	{
		std::cout << "MD5_Update failed..." << std::endl;
		return "";
	}

	//3. 计算结果
	ret = MD5_Final(md, &c);
	if (1 != ret)
	{
		std::cout << "MD5_Final failed..." << std::endl;
		return "";
	}

	//4. 输出结果
	memset(buf, 0, MD5_DIGEST_LENGTH * 2 + 1);
	for (int i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf((char*)&buf[i * 2], "%02X", md[i]);
	}

	return std::string((char*)buf);
}

std::string getMD5_3(const std::string& str)
{
	unsigned char md[MD5_DIGEST_LENGTH] = { 0 };
	unsigned char buf[MD5_DIGEST_LENGTH * 2 + 1] = { 0 };

	MD5((const unsigned char *)str.c_str(), str.size(), md);

	memset(buf, 0, MD5_DIGEST_LENGTH * 2 + 1);
	for (int i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf((char*)&buf[i * 2], "%02X", md[i]);
	}

	return std::string((char*)buf);
}

std::string getMD5_4(const std::string& str)
{
	unsigned char dst[0x10] = { 0 };
	unsigned int dst_len = 0x10;
	size_t src_len = str.size();

	EVP_MD_CTX *ctx;
	ctx = EVP_MD_CTX_create();
	EVP_MD_CTX_init(ctx);
	EVP_DigestInit(ctx, EVP_md5());
	if (EVP_DigestUpdate(ctx, str.c_str(), src_len))
	{
		if (EVP_DigestFinal(ctx, dst, &dst_len))
		{
			EVP_MD_CTX_cleanup(ctx);
		}
	}

	char buf[33] = { 0 };
	char tmp[3] = { 0 };
	for (auto i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf_s(tmp, "%02x", dst[i]);
		strcat_s(buf, tmp);
	}

	return std::string((char*)buf);
}

int main()
{
	auto data = "Hello World! 爱看书的小沐 2022.";

	std::cout << "输入:" << std::endl;
	std::cout << data << std::endl;

	std::cout << "输出:" << std::endl;
	std::cout << getMD5_1(std::string(data)).c_str() << std::endl;
	std::cout << getMD5_2(std::string(data)).c_str() << std::endl;
	std::cout << getMD5_3(std::string(data)).c_str() << std::endl;
	std::cout << getMD5_4(std::string(data)).c_str() << std::endl;
	
	system("pause");
	return 0;
}

运行结果如下:
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第22张图片

4.3 SHA256实现

#include 
 #include 
 #include 
 #include 

 int main(void)
 {
     EVP_MD_CTX *ctx = NULL;
     EVP_MD *sha256 = NULL;
     const unsigned char msg[] = {
         0x00, 0x01, 0x02, 0x03
     };
     unsigned int len = 0;
     unsigned char *outdigest = NULL;
     int ret = 1;

     /* Create a context for the digest operation */
     ctx = EVP_MD_CTX_new();
     if (ctx == NULL)
         goto err;

     /*
      * Fetch the SHA256 algorithm implementation for doing the digest. We're
      * using the "default" library context here (first NULL parameter), and
      * we're not supplying any particular search criteria for our SHA256
      * implementation (second NULL parameter). Any SHA256 implementation will
      * do.
      */
     sha256 = EVP_MD_fetch(NULL, "SHA256", NULL);
     if (sha256 == NULL)
         goto err;

    /* Initialise the digest operation */
    if (!EVP_DigestInit_ex(ctx, sha256, NULL))
        goto err;

     /*
      * Pass the message to be digested. This can be passed in over multiple
      * EVP_DigestUpdate calls if necessary
      */
     if (!EVP_DigestUpdate(ctx, msg, sizeof(msg)))
         goto err;

     /* Allocate the output buffer */
     outdigest = OPENSSL_malloc(EVP_MD_get_size(sha256));
     if (outdigest == NULL)
         goto err;

     /* Now calculate the digest itself */
     if (!EVP_DigestFinal_ex(ctx, outdigest, &len))
         goto err;

     /* Print out the digest result */
     BIO_dump_fp(stdout, outdigest, len);

     ret = 0;

  err:
     /* Clean up all the resources we allocated */
     OPENSSL_free(outdigest);
     EVP_MD_free(sha256);
     EVP_MD_CTX_free(ctx);
     if (ret != 0)
        ERR_print_errors_fp(stderr);
     return ret;
 }

5、使用openssl(命令行openssl.exe)

5.1 私钥公钥生成

这两者的工作机制是,通过公钥加密的数据只能通过对应的私钥才能解密查看。而通过私钥加密的数据如果能被对应的公钥解开则可断定数据由该私钥的所有者发送。
前一个机制可以用于加密消息的传递,后一个则可以用于身份的确认,凡事通过公钥A能解密的数据一定是私钥A的所有者发送的数据。

默认情况下,openssl 输出格式为 PKCS#1-PEM

  • 生成RSA私钥(无加密)
openssl genrsa -out rsa_private.key 2048
  • 生成RSA公钥
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
  • 生成RSA私钥(使用aes256加密)
openssl genrsa -aes256 -passout pass:123456 -out rsa_aes_private.key 2048
  • 生成公钥(需提供密码)
openssl rsa -in rsa_aes_private.key -passin pass:123456 -pubout -out rsa_public.key
  • 私钥转非加密
openssl rsa -in rsa_aes_private.key -passin pass:123456 -out rsa_private.key
  • 私钥转加密
openssl rsa -in rsa_private.key -aes256 -passout pass:123456 -out rsa_aes_private.key
  • 查看私钥明细(使用-pubin参数可查看公钥明细)
openssl rsa -in rsa_private.key -noout -text

5.2 自签名证书生成

  • 生成 RSA 私钥和自签名证书
    req是证书请求的子命令,-newkey rsa:2048 -keyout private_key.pem 表示生成私钥(PKCS8格式),-nodes 表示私钥不加密,若不带参数将提示输入密码;-x509表示输出证书,-days365 为有效期,此后根据提示输入证书拥有者信息;若执行自动输入,可使用-subj选项。
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 365 -out cert.crt
或
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 365 -out cert.crt -subj "/C=CN/ST=GD/L=SZ/O=xx/OU=dev/CN=yyy.com/[email protected]"
  • 使用 已有RSA 私钥生成自签名证书
openssl req -new -x509 -days 365 -key rsa_private.key -out cert.crt

-new 指生成证书请求,加上-x509 表示直接输出证书,-key 指定私钥文件。

  • 查看证书细节
openssl x509 -in cert.crt -noout -text
  • 另外,openssl命令方式生成公钥、私钥、证书汇总如下:
#1.生成私钥文件
openssl genrsa -des3 -out privkey.pem 2048
# or 无密码
openssl genrsa -out privkey.pem 2048

#2.生成证书请求文件和证书文件
openssl req -new -key privkey.pem -out cert.csr
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 3650

#3.生成公钥文件
openssl rsa -in privkey.pem -inform pem -pubout -out pubkey.pem

#4.查看密钥信息
openssl rsa -noout -text -in privkey.pem
  • 另外,服务器客户端证书生成的命令汇总如下:
#生成服务端证书
#使用openssl工具生成一个RSA私钥
openssl genrsa -des3 -out server.key 2048
#查看生成的私钥
openssl rsa -text -in server.key
#创建证书签名请求CSR文件
openssl req -new -key server.key -out server.csr
#查看csr文件
openssl req -text -in server.csr -noout
#生成CA证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

#生成客户端证书
#先要生成私钥
openssl genrsa -out client.key 2048
#生成请求文件
openssl req -new -key client.key -out client.csr
#签名
openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.crt

5.3 加密文件

  • 生成私钥
openssl genrsa -out Key.pem -f4 2048

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第23张图片

  • 从私钥导出公钥
openssl rsa -in Key.pem -pubout -out Key_pub.pem

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第24张图片

  • 将字符串”Hello World, 爱看书的小沐!”存放到文件msg.bin作为测试文件
echo "Hello World, 爱看书的小沐!" > msg.bin

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第25张图片
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第26张图片

  • 查看文件内容(以十六进制)
hexdump -Cv msg.bin

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第27张图片

  • 使用公钥Key_pub.pem对测试数据msg.bin进行加密生成msg.bin.enc
openssl rsautl -in msg.bin -out msg.bin.enc -inkey Key_pub.pem -pubin -encrypt -pkcs

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第28张图片

  • 查看加密后的数据
hexdump -Cv msg.bin.enc

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第29张图片
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第30张图片

  • 使用私钥Key.pem对加密后的数据msg.bin.enc进行解密,并将结果存放到msg.bin.dec文件中
openssl rsautl -in msg.bin.enc -out msg.bin.dec -inkey Key.pem -decrypt -pkcs

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第31张图片

  • 查看解密的内容
hexdump -Cv msg.bin.dec

在这里插入图片描述
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第32张图片

6、使用openssl(python)

https://pypi.org/project/pyOpenSSL/

pyOpenSSL supports the same platforms and releases as the upstream cryptography project does. Currently that means: 1.1.0,1.1.1,3.0。

  • 安装该库命令,如下:
pip install pyopenssl

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第33张图片

  • 打印SSL证书路径:
import base64
from OpenSSL import SSL 
 
print(SSL._CERTIFICATE_PATH_LOCATIONS)

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第34张图片

  • 生成一个私钥(生成具有给定位数的给定类型的密钥对):
from OpenSSL import crypto

k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 2048)
print(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第35张图片

  • 生成私钥和证书
from OpenSSL import crypto

CERT_FILE = "d:/test.cert"
KEY_FILE = "d:/test.key"

def SelfSignedCertificate():
    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 1024)

    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = "IL"
    cert.get_subject().ST = "Jerusalem"
    cert.get_subject().L = "Jerusalem"
    cert.get_subject().OU = "DevOps Loft"
    cert.get_subject().CN = "foo"#gethostname()
    cert.set_serial_number(1000) #SystemRandom().randint(2048 ** 8, 4096 ** 8)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(10*365*24*60*60)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha1')

    with open(CERT_FILE, "wb") as cert_f:
        cert_f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
    with open(KEY_FILE, "wb") as key_f:
        key_f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k)) 

SelfSignedCertificate()

运行结果如下:
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第36张图片
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第37张图片

  • 查看上面生成的证书文件内容:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import OpenSSL
import time
from dateutil import parser

# openssl x509 -inform DER -in test.cer -out certificate.crt
with open("d:/test.cert", "r") as fp:
    crt_data = fp.read()

cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, crt_data)
certIssue = cert.get_issuer()

print("证书版本:            ", cert.get_version() + 1)
print("证书序列号:          ", hex(cert.get_serial_number()))
print("证书中使用的签名算法: ", cert.get_signature_algorithm().decode("UTF-8"))
print("颁发者:              ", certIssue.commonName)
datetime_struct = parser.parse(cert.get_notBefore().decode("UTF-8"))
print("有效期从:             ", datetime_struct.strftime('%Y-%m-%d %H:%M:%S'))
datetime_struct = parser.parse(cert.get_notAfter().decode("UTF-8"))
print("到:                   ", datetime_struct.strftime('%Y-%m-%d %H:%M:%S'))
print("证书是否已经过期:      ", cert.has_expired())
print("公钥长度", cert.get_pubkey().bits())
print("公钥:\n", OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey()).decode("utf-8"))
print("主体信息:")
print("CN : 通用名称  OU : 机构单元名称")
print("O  : 机构名    L  : 地理位置")
print("S  : 州/省名   C  : 国名")

for item in certIssue.get_components():
    print(item[0].decode("utf-8"), "  ——  ", item[1].decode("utf-8"))

print(cert.get_extension_count())

运行结果如下:
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第38张图片

7、个人测试

7.1 软件License许可证文件实现(C++)

如何保护软件版权,最常用的办法就是设计一套license验证框架。
这里基于OpenSSL库的加密功能,使用C++编写逻辑代码,WTL编写界面代码,实现一个简单的许可证应用小程序(包括许可申请,许可生成,许可验证等功能)。

  • 申请界面(客户端)
    此处省略。
  • 生成界面(管理端)
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第39张图片
  • 生成的许可证文件内容如下:
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第40张图片

7.2 批量加密图片文件(python)

openssl genrsa -out rsa_private.key 2048
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
openssl rsa -in rsa_public.key -noout -text -pubin

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第41张图片

  • 加密前:
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第42张图片

  • 加密后:
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第43张图片
    【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第44张图片

  • 相关代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @File    : 批量加密图片v2.py
# @Time    : 2022-8-10
# @Author  : 爱看书的小沐
# @blog    : https://blog.csdn.net/hhy321
# @Language: python3.9, win10 x64
# @Version : 2.0
# @Desc    : 批量加密和解密图片文件

import os
import random

def generate_random_str(randomlength=16):
    """
    生成一个指定长度的随机字符串(使用指定的字符集合填充)
    """
    random_str =''
    base_str ='ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
    length =len(base_str) -1
    for i in range(randomlength):
        random_str +=base_str[random.randint(0, length)]
    return random_str

def generate_random_int(randomlength=16):
    """
    生成一个指定长度的随机数字串(使用随机的0~254数字填充)
    """
    random_int = []
    for i in range(randomlength):
        random_int.append(random.randint(25, 254))
    return random_int

def generate_random_int(randomlength=16, filldata = [], addToENd = False):
    """
    生成一个指定长度的随机数字串(使用固定字符集合填充)
    """
    fill_len = len(filldata)
    random_int = []
    if randomlength < fill_len:
        return generate_random_int(randomlength)

    for i in range(randomlength):
        if addToENd == False:
            if i < fill_len:
                random_int.append(filldata[i])
            else:
                random_int.append(random.randint(25, 254))
        else:
            if i < randomlength - fill_len:
                random_int.append(random.randint(25, 254))
            else:
                random_int.append(filldata[i - (randomlength - fill_len)])
    return random_int

def getXor(text, key):
    """
    字符串异或计算
    """
    text_bytes = []
    for i in range(0, len(text)):
        text_bytes.append((text[i] ^ ord(key[i % len(key)])))
    return text_bytes

def encrypt_image(image_file, encrypt_file):
    """
    加密图片文件
    """
    f = open(image_file, 'rb')
    fw = open(encrypt_file, 'wb')
    data = f.read()

    ## 原始的文件头128(异或运算)
    header_old = data[0:128]
    key = '123456'
    header_old_xor = getXor(header_old, key)
    header_old_xor = bytes(bytearray(header_old_xor))
    print(type(header_old_xor), header_old_xor)

    ## 新的文件头128(随机数填充)
    header_new = generate_random_int(128)
    header_tag = "FXIMAGEv100"
    for c in range(len(header_tag)):
        header_new[c] = ord (header_tag[c])
    header_new = bytes(bytearray(header_new))

    ## 读取openssl公钥文件512
    public_key = open(r"d:\rsa_public.key", 'rb').read()
    rand_data = generate_random_int(512, public_key, True)
    rand_data = bytes(bytearray(rand_data))

    ## 生成加密后的新图片文件
    fw.write(header_new)
    fw.write(data[128:])
    fw.write(header_old_xor)
    fw.write(rand_data)
    fw.close()
    f.close()
    
def findAllFile(base):
    for root, ds, fs in os.walk(base):
        for f in fs:
            fullname = os.path.join(root, f)
            yield fullname

def main():
    src_dir = 'D:\Image'
    dest_dir = 'D:\Image2'
    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    for f in findAllFile(src_dir):
        print(f)
        dirname, filename = os.path.split(f)
        dirname_encrypt = dirname.replace(src_dir, dest_dir)
        if not os.path.exists(dirname_encrypt):
            os.makedirs(dirname_encrypt)
        filename_encrypt = os.path.splitext(filename)[0] + r".fximage"
        encrypt_image(f, dirname_encrypt + "\\" + filename_encrypt )

    print("ok")
    
if __name__ == '__main__':
    main()    

7.3 图片Arnold置乱算法(python)

  • (1)Arnold置乱算法

Arnold置乱俗称猫脸变换,因为最开始用的Demo图是一张猫脸。

这个算法可以让一张图片从有序变成无序,逆变换可以让他从无序变成有序,同时他还具有一定的周期性,一直正向变化也可以从有序->无序->有序,但由于加密密钥方式很多,置乱的周期也可能不一样。

图像变换(加密过程):
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第45张图片
其中x和y表示坐标,new表示变换以后的坐标,ori表示原始的坐标,a和b是两个可选的参数,mod为求余数操作,N是图像的长或者宽,这里只考虑长度和宽度相等的图像,上式表示的就是“图像的坐标变换”。

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第46张图片

对应的逆变换(解密过程):
【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第47张图片

【小沐学C++】C++ OpenSSL库编译及使用(VS2017,Python)_第48张图片

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @File    : test_arnold.py
# @Time    : 2022-8-14
# @Author  : 爱看书的小沐
# @blog    : https://blog.csdn.net/hhy321
# @Language: python3.9, win10 x64
# @Version : 1.0
# @Desc    : 图片Arnold置乱算法
## pip install opencv-python

import numpy as np
import cv2

def arnold_encode(image, shuffle_times, a, b):
    """ 
    Arnold shuffle for rgb image
    """
    # 1:创建新图像
    [ROW, COL, COMP] = img.shape
    arnold_image = np.zeros(shape=image.shape, dtype='uint8')

    # 2:遍历像素坐标变换
    for time in range(shuffle_times):
        for ori_x in range(ROW):
            for ori_y in range(COL):
                new_x = (1*ori_x + b*ori_y) % ROW
                new_y = (a*ori_x + (a*b+1)*ori_y) % COL
                arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]
                
    return arnold_image

def arnold_decode(image, shuffle_times, a, b):
    """ 
    Dearnold shuffle for rgb image
    """
    # 1:创建新图像
    [ROW, COL, COMP] = img.shape
    arnold_image = np.zeros(shape=image.shape, dtype='uint8')
    
    # 2:遍历像素坐标变换
    for time in range(shuffle_times):
        for ori_x in range(ROW):
            for ori_y in range(COL):
                new_x = ((a*b+1)*ori_x - b*ori_y) % ROW
                new_y = (-a*ori_x + 1*ori_y) % COL
                arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]

    return arnold_image

if __name__ == '__main__': 
    img = cv2.imread('d:/test.jpg', cv2.IMREAD_UNCHANGED)
    a = 1
    b = 1
    T = 1 #迭代次数

    cv2.imshow('origin image', img)

    img_arnold = arnold_encode(img, T, a, b)
    cv2.imshow('arnold image', img_arnold)

    img_dearnold = arnold_decode(img_arnold, T, a, b)
    cv2.imshow('dearnold image', img_dearnold)

    cv2.waitKey()
    cv2.destroyAllWindows()

运行结果如下:(原始图片,加密图片,解密图片, a=1,b=1,T=1)

运行结果如下:(原始图片,加密图片,解密图片, a=5,b=3,T=2)


结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

你可能感兴趣的:(C/C++,Python,c++,ssl,md5,openssl,perl)