基於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.\n");
return;
}
outfp = fopen("test.txt","w");//打開編碼后保存的文件
if(outfp == NULL)
{
printf("Open File \"test.txt\" For Write Err.\n");
return;
}
EVP_EncodeInit(ctx);//Base64編碼初始化
printf("文件\"Test.dat\" Base64編碼后為:\n");
//循環讀取原文,並調用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\"文件.\n\n\n");
}
//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.\n");
return;
}
outfp = fopen("test-1.dat","wb");//打開解碼后保存的文件
if(outfp == NULL)
{
printf("Open File \"test-1.txt\" For Write Err.\n");
return;
}
EVP_DecodeInit(ctx);//Base64解碼初始化
printf("開始對文件\"Test.txt\" Base64解碼...\n\n");
//循環讀取原文,並調用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\"\n\n\n");
}
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
如果你覺得本文對你有幫助,請點一下左下角的“好文要頂”和“收藏該文”