基于openEuler的OpenSSL编译安装和编程基础
有关OpenSSL的编译、安装、使用、编程我写过一篇博客Linux下OpenSSL的安装与使用.
由于学校跟华为合作“智能基座”产教融合协同育人基地项目,我们把学习平台从原来的X64+Ubuntu的架构换成ARM64(鲲鹏)+openEuler的架构。
ARM64 + openEuler环境可以在华为云购买ECS,同学们使用优惠券注意按下图选项购买:
特别提醒:做完实验一定要关机,否则优惠券会很快用完!!!
另外还可以自己购买个树莓派,自己安装openEuler,可以参考这个教程树莓派openEuler安装.
下面演示基于华为云ECS,鲲鹏+openEuler架构。
远程登录openEuler,我们看一下openEuler默认有没有安装OpenSSL,如下图所示,openEuler默认已经安装好了OpenSSL:
当前openEuler系统安装的OpenSSL版本是1.1.1d,现在(2021.04)OpenSSL最新的版本是1.1.1k,还有一个问题,openEuler中没有变成开发需要的头文件。我们需要自己下载OpenSSL的源码编译安装。
OpenSSL编译安装
- 我们去OpenSSL官网下载最新版本OpenSSL 1.1.1k的源码openssl-1.1.1k.tar.gz,然后把代码上传到openEuler云服务器中。
- 建立两个文件夹,分别放置OpenSSL的源码和安装路径,记住
pwd
运行的结果/root/rocopenssl
:
mkdir rocopensslsrc rocopenssl
cd rocopenssl
pwd
- 解压源代码到
rocopensslsrc
文件夹:
tar -zxvf openssl-1.1.1k.tar.gz -C rocopensslsrc
- 配置编译安装路径(/root/rocopenssl),和openEuler系统默认的不同。
cd rocopensslsrc/openssl-1.1.1k
./config --prefix=/root/rocopenssl
- 编译(make时间稍长,耐心等待),测试、安装,其中测试步骤可选:
make
make test
make install
- 查看安装后的版本,确定是最新安装的1.1.1k版:
cd ~/rocopenssl
./bin/openssl version
注意用到的库还是旧版本的,这个问题怎么解决留作思考题吧
- 大家要注意的是rocopenssl下的include和lib的路径,我们后面编程要用到。
/root/rocopenssl/include
/root/rocopenssl/lib
以上步骤可以使用下面的installopenssl.sh脚本完成:
#! /bin/sh
cd
if [ ! -d rocopenssl ];
then
mkdir rocopenssl
mkdir rocopensslsrc
fi
if [ ! -f ~/openssl-1.1.1k.tar.gz ];
then
wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz
tar -zxvf ~/openssl-1.1.1k.tar.gz -C ~/rocopensslsrc
cd ~/rocopensslsrc/openssl-1.1.1k
./config --prefix=/root/rocopenssl
make
make test
make install
~/rocopenssl/bin/openssl version
fi
OpenSSL命令的使用
学会工具第一招,学会查看帮助文档,OpenSSL命令的帮助使用openssl help
查看:
OpenSSL命令下面有很多子命令分为三类:标准命令,消息摘要命令和密码命令。这些命令我们有两种用法,以最简单的产看版本命令为例,我们可以先输入openssl
进入OpenSSL的功能界面后输入version
,也可以直接在openEuler终端中直接输入openssl version
进行查看,在实际应用中我们多采用后一种方法。
对于子命令的使用帮助,我们可以有两种方式查看openssl help xxsubcmd
或 openssl xxsubcmd --help
,比如用这两种方法查看消息摘要子命令的用法:
openssl dgst 常用选项(options)有:
[-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] :指定一种摘要算法
-out filename:将摘要值保存到指定文件中
比如我们用国密算法sm3计算besti
的摘要,注意子命令的两种用法以及管道的用法:
把besti
放到besti.txt文件中,计算文件的摘要:
如何使用随机数产生对称加密算法的密钥?如何使用国密算法sm4进行对称加解密?如果产生sm2的公私钥对?如果用SM2算法加密解密,签名验签?这些作为思考题吧。
OpenSSL编程
密码算法库的功能非常强大,是OpenSSL的基础,它实现了现代密码学大部分主流的密码算法和标准,主要包括公开密钥(非对称)算法、对称加密算法、信息摘要算法、X509 数字证书标准、PKCS12个人信息交换语法标准、PKCS7 加密消息语法标准、OCSP 在线证书状态查询协议、 CRL 证书吊销列表等标准。同时 OpenSSL 还提供了Engine 机制;利用 Engine 可以将加密卡、加密机这样的外部硬件算法模块无缝集成到 OpenSSL 中。密码算法库在 Windows 下编译后其库文件为 libeay32.lib(如果编译成动态库则为 libeay32.dll),在 Linux 编译后其库文件名称为 libcrypto.a。
现在的版本支持国密算法如SM2,SM3,SM4等算法。
简单测试
编写一个测试代码test_openssl.c:
#include <stdio.h>
#include <openssl/evp.h>
int main(){
OpenSSL_add_all_algorithms();
return 0;
}
然后用下面命令编译:
gcc -o to test_openssl.c -I /root/rocopenssl/include -L /root/rocopenssl/lib -lcrypto -lpthread
执行./to;echo $?
,结果打印0.
BASE64算法
OpenSS1在 Evp.h中提供了Base64 编码和解码的函数。Base64 编码就是把二进制数据转换为可见的 ASCIⅡ字符。Base64 解码是相反的过程。Base64编码后的数据方便在 Web 中传输以及可视化的复制和粘贴。
OpenSSL 进行 Base64 编码的函数主要有EVP_EncodeInit、EVP_EncodeUpdate、EVP_EncodeFinal和 EVP_EncodeBlock
。其中 EVP_EncodeInit、EVP_EncodeUpdate
和 EVP_EncodeFinal
适用于处理不定长的大数据,EVP_EncodeBlock
适用于处理短数据。
OpenSSL 进行 Base64 解码的函数主要有EVP_Decodelnit、EVP_DecodeUpdate、EVP_DecodeFinal和 EVP_DecodeBlock
。其中 EVP_DecodeInit、EVP_DecodeUpdate
和 EVP_DecodeFinal
适用于处理不定长的大数据,EVP_DecodeBlock
适用于处理短数据。
上面的函数可以完成消息的编码和解码,它们均定义在 openssl/evp.h
文件中。
我们要注意的是XXXInit,XXXUpdte,XXXFinal的编程模式。
我们写一个BASE64的测试代码testbase64.c
:
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
//Base64编码
void tEVP_Encode()
{
EVP_ENCODE_CTX *ctx;
ctx = EVP_ENCODE_CTX_new(); //EVP编码结构体
unsigned char in[1024]; //输入数据缓冲区
int inl; //输入数据长度
char out[2048]={0}; //输出数据缓冲区
int outl; //输出数据长度
FILE *infp; //输入文件句柄
FILE *outfp; //输出文件句柄
infp = fopen("test.dat","rb");//打开待编码的文件
if(infp == NULL)
{
printf("Open File "Test.dat" for Read Err.
");
return;
}
outfp = fopen("test.txt","w");//打开编码后保存的文件
if(outfp == NULL)
{
printf("Open File "test.txt" For Write Err.
");
return;
}
EVP_EncodeInit(ctx);//Base64编码初始化
printf("文件"Test.dat" Base64编码后为:
");
//循环读取原文,并调用EVP_EncodeUpdate计算Base64编码
while(1)
{
inl = fread(in,1,1024,infp);
if(inl <= 0)
break;
EVP_EncodeUpdate(ctx,out,&outl,in,inl);//编码
fwrite(out,1,outl,outfp);//输出编码结果到文件
printf("%s",out);
}
EVP_EncodeFinal(ctx,out,&outl);//完成编码,输出最后的数据。
fwrite(out,1,outl,outfp);
printf("%s",out);
fclose(infp);
fclose(outfp);
printf("对文件"Test.dat" Base64编码完成,保存到"test.txt"文件.
");
}
//Base64解码
void tEVP_Decode()
{
EVP_ENCODE_CTX *ctx;
ctx = EVP_ENCODE_CTX_new(); //EVP编码结构体
char in[1024]; //输入数据缓冲区
int inl; //输入数据长度
unsigned char out[1024]; //输出数据缓冲区
int outl; //输出数据长度
FILE *infp; //输入文件句柄
FILE *outfp; //输出文件句柄
infp = fopen("test.txt","r");//打开待解码的文件
if(infp == NULL)
{
printf("Open File "Test.txt" for Read Err.
");
return;
}
outfp = fopen("test-1.dat","wb");//打开解码后保存的文件
if(outfp == NULL)
{
printf("Open File "test-1.txt" For Write Err.
");
return;
}
EVP_DecodeInit(ctx);//Base64解码初始化
printf("开始对文件"Test.txt" Base64解码...
");
//循环读取原文,并调用EVP_DecodeUpdate进行Base64解码
while(1)
{
inl = fread(in,1,1024,infp);
if(inl <= 0)
break;
EVP_DecodeUpdate(ctx,out,&outl,in,inl);//Base64解码
fwrite(out,1,outl,outfp);//输出到文件
}
EVP_DecodeFinal(ctx,out,&outl);//完成解码,输出最后的数据。
fwrite(out,1,outl,outfp);
fclose(infp);
fclose(outfp);
printf("对文件"Test.txt" Base64解码完成,保存为"test-1.dat"
");
}
int main()
{
tEVP_Encode();
tEVP_Decode();
return 0;
}
代码中有中文,编译运行可能出现乱码,使用gcc编译时可以使用如下参数:
- -finput-charset 指定源文件(保存文件时选择)的编码方式(若不指定,编译器默认是UTF-8)
- -fexec-charset 指定可执行程序中的字符以什么编码方式来表示,默认是UTF-8
编译代码的命令是:
gcc -o testbase64 testbase64.c -I /root/rocopenssl/include -L /root/rocopenssl/lib -lcrypto -lpthread -finput-charset=GBK -fexec-charset=UTF-8
测试中的用到一个test.dat 是个二进制文件,可以用echo命令生成,或者用二进制编辑工具生成。
执行./testbase64
,结果如下图:
作业
- 两人一组
- 基于Socket实现TCP通信,一人实现服务器,一人实现客户端
- 研究OpenSSL算法,测试对称算法中的SM4,非对称算法中的SM2,Hash算法中的SM3
- 选用合适的算法,基于混合密码系统实现对TCP通信进行机密性、完整性保护。
- 学有余力者,对系统进行安全性分析和改进。
参考资料
欢迎关注“rocedu”微信公众号(手机上长按二维码)
做中教,做中学,实践中共同进步!
-
版权声明:自由转载-非商用-非衍生-保持署名| Creative Commons BY-NC-ND 3.0
如果你觉得本文对你有帮助,请点一下左下角的“好文要顶”和“收藏该文”