密碼引擎的設計與實現
實驗一 密碼引擎-0-OpenEuler ECS構建
登入自己的華為雲賬號,參考附件圖示,構建基於鯤鵬和OpenEuler的ECS。 登入進OpenEuler系統,熟悉系統使用,注意OpenEuler安裝工具使用sudo yum install ... 登入進OpenEuler系統,提交執行who命令的截圖 加分項:使用yum install 安裝C程式設計工具,以及自己的常用工具,提交安裝後測試使用的截圖。
構建基於鯤鵬和OpenEuler的ECS可參考華為雲服務購買及基礎實驗,記得照著下圖修改
登入進OpenEuler系統,熟悉系統使用,注意OpenEuler安裝工具使用sudo yum install ...
進入控制檯,點選遠端登入之後,點選CloudShell登入。
填入設定的密碼後,點選連線。
登入進OpenEuler系統,提交執行who命令的截圖
加分項:使用yum install 安裝C程式設計工具,以及自己的常用工具,提交安裝後測試使用的截圖。
實驗一 密碼引擎-1-OpenEuler-OpenSSL編譯
1. 下載最新的OpenSSL原始碼 2. 用自己的8位學號建立一個資料夾,cd 你的學號,用pwd獲得絕對路徑 3. 參考https://www.cnblogs.com/rocedu/p/5087623.html先在Ubuntu中完成OpenSSL編譯安裝,然後在OpenEuler中重現 ./config --prefix=..(學號目錄的絕對路徑)指定OpenSSL編譯連結 4. 提交 test_openssl.c 編譯執行截圖 5. 加分項:在Windows中編譯OpenSSL,記錄編譯過程,提交相關文件(推薦MarkDown格式)
注:我的ubuntu用的是wsl(其實這個時候可以選擇使用老師給的openssl-master也可以使用原來wsl自帶的openssl)。
以下我使用老師提供的openssl-master:
已知老師為我們提供了openssl-master.zip,首先我們可以解壓縮到新創的20181217資料夾。
在wsl中的操作:
1 |
cd openssl-master 進入剛剛解壓縮的資料夾
|
執行下面的操作:
1 2 3 4 5 |
./configure
make
sudo make install
|
這樣就安裝好了。
安裝好了之後,出現的問題及解決:
檢視openssl版本時,出錯了:
openssl: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory
經過上網查詢,可知但我們輸入這兩條指令時,可以成功解決上述問題~
1 2 |
ln -s /usr/local/lib/libssl.so.3 /usr/lib/libssl.so.3
ln -s /usr/local/lib/libcrypto.so.3 /usr/lib/libcrypto.so.3
|
注意:到底是lib還是lib64需要自己進入資料夾去親自檢視。
再此檢視openssl版本時,顯示是成功的:
在ubuntu下編譯:
1 |
gcc -o to test_openssl.c -I /usr/local/ssl/inlcude -L /usr/local/ssl/lib -ldl -lpthread -lcrypto
|
可知編譯成功!
在華為雲中,同樣我們要安裝openssl,和在wsl中安裝的方式一模一樣。(首先,我們要先建立20181217資料夾,然後可以直接把openssl-master.zip包拖到華為雲的20181217資料夾下,再進行解壓縮~)
出現了和wsl中一樣的問題:
[root@ecs-cindy openssl-master]# openssl version
openssl: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory
經過上網查詢,可知但我們輸入這兩條指令時,可以成功解決上述問題~
1 2 |
ln -s /usr/local/lib/libssl.so.3 /usr/lib64/libssl.so.3
ln -s /usr/local/lib/libcrypto.so.3 /usr/lib64/libcrypto.so.3
|
可知最終編譯成功了。
加分項:在Windows中編譯OpenSSL,記錄編譯過程,提交相關文件
CodeBlocks配置openssl
-
加靜態庫
(先啟用專案)選單欄->Project->Build Options->Debug->Linker settings->Add 自己openssl安裝目錄下/lib下所有.lib檔案(選擇時使用Ctrl+A)
-
加動態庫
選單欄->Project->Build Options->Debug->Search directories->Linker->Add 動態庫的目錄(參考前面安裝時的選項,設定後為/bin下)
-
加標頭檔案
選單欄->Project->Build Options->Debug->Search directories->Compiler->Add 安裝目錄/include
測試Base64效果:
2.Virtual Studio 2019實現openssl編譯
eg:實現sm3:
由此可知windows下openssl編譯成功!
實驗一 密碼引擎-2-OpenEuler-OpenSSL測試
在Ubuntu編寫程式碼測試OpenSSL功能,包含Base64,SM2,SM3,SM4演算法的呼叫,然後在OpenEuler中重現 提交程式碼連結和執行結果截圖 加分項:在Windows中重現(已重現)
程式碼連結:https://gitee.com/csq200215/csq/tree/master/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%8B%EF%BC%89%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%AE%9E%E9%AA%8C
Base64:(使用老師給我們的Openssl-Test.zip)
1.在wsl實現
注意:老師給的程式碼在ubuntu下是不能跑通的,我們需要對EVP_Base64資料夾中的main.c檔案進行修改(或者直接再重新生成一個Base64.c)
Base64.c如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
#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;
}
|
我們可以直接直接在原資料夾中生成。
一、 執行命令將Base64.c編譯成可執行檔案Base64。
1 |
gcc -o Base64 Base64.c -I /usr/local/ssl/inlcude -L /usr/local/ssl/lib -ldl -lpthread -lcrypto
|
另一種執行方法~gcc -o Base64 Base64.c -lpthread -lcrypto
2.華為雲
在OpenEuler中重現。
首先我們把下載好的 Openssl-Test.zip檔案直接拖到華為雲的20181217資料夾下。
1 |
unzip Openssl-Test.zip 實現解壓縮。
|
進入Openssl-Test資料夾中,再進入EVP_Base64資料夾:
注意:老師給的程式碼在ubuntu下是不能跑通的,我們需要對EVP_Base64資料夾中的main.c檔案進行修改(或者直接再重新生成一個Base64.c)。
和之前一樣~
實現:
可知可以成功實現。
在windows中重現:
二、實現SM2
編譯過程:
gcc sm2_create_key_pair.c test_demo.c sm2_encrypt_and_decrypt.c test_sm2_encrypt_and_decrypt.c -o mysm2 -lcrypto
執行過程:
在華為雲上執行過程:
執行結果:
可知成功實現。
在windows上的 VS中重現:
三、SM3
程式碼:
mysm3.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
void tDigest()
{
unsigned char sm3_value[EVP_MAX_MD_SIZE]; //儲存輸出的摘要值的陣列
int sm3_len, i;
EVP_MD_CTX *sm3ctx; //EVP訊息摘要結構體
sm3ctx = EVP_MD_CTX_new(); //呼叫函式初始化
char msg1[] = "Test Message1" ; //待計算摘要的訊息1
char msg2[] = "Test Message2" ; //待計算摘要的訊息2
EVP_MD_CTX_init(sm3ctx); //初始化摘要結構體
EVP_DigestInit_ex(sm3ctx, EVP_sm3(), NULL); //設定摘要演算法和密碼演算法引擎,這裡密碼演算法使用sm3,演算法引擎使用OpenSSL預設引擎即軟演算法
EVP_DigestUpdate(sm3ctx, msg1, strlen(msg1)); //呼叫摘要UpDate計算msg1的摘要
EVP_DigestUpdate(sm3ctx, msg2, strlen(msg2)); //呼叫摘要UpDate計算msg2的摘要
EVP_DigestFinal_ex(sm3ctx, sm3_value, &sm3_len); //摘要結束,輸出摘要值
EVP_MD_CTX_reset(sm3ctx); //釋放記憶體
printf( "原始資料%s和%s的摘要值為:\n" ,msg1,msg2);
for (i = 0; i < sm3_len; i++)
{
printf( "0x%02x " , sm3_value[i]);
}
printf( "\n" );
}
int main()
{
OpenSSL_add_all_algorithms();
tDigest();
return 0;
}
|
初始化函式EVP_MD_CTX_init
函式功能:初始化一個 EVP_MD_CTX 結構體。只有呼叫該函式初始化後,EVP_MD_CTX結構體才能在其他函式中呼叫。
函式定義:
void EVP_MD_CTxinit(EVP MD CTX *ctx):
在ubuntu下實現:
執行命令:
1 |
gcc -o mysm3 mysm3.c -lpthread -lcrypto
|
在華為雲上實現:
在windows下的VS 2019中重現
四、SM4
程式碼:
mysm4.c :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
void tEVP_Encrypt()
{
unsigned char key[EVP_MAX_KEY_LENGTH]; //金鑰
unsigned char iv[EVP_MAX_KEY_LENGTH]; //初始化向量
EVP_CIPHER_CTX* ctx; //EVP演算法上下文
unsigned char out [1024]; //輸出密文緩衝區
int outl; //密文長度
int outltmp;
const char *msg= "Hello OpenSSL" ; //待加密的資料
int rv;
int i;
//初始化函式才能用!
ctx = EVP_CIPHER_CTX_new();
//設定key和iv(可以採用隨機數和可以是使用者輸入)
for (i=0;i<24;i++)
{
key[i]=i;
}
for (i=0;i<8;i++)
{
iv[i]=i;
}
//初始化密碼演算法結構體
EVP_CIPHER_CTX_init(ctx);
//設定演算法和金鑰以
rv = EVP_EncryptInit_ex(ctx,EVP_sm4_cbc(),NULL,key,iv);
if (rv!=1)
{
printf( "Err\n" );
return ;
}
//資料加密
rv = EVP_EncryptUpdate(ctx, out ,&outl,( const unsigned char *)msg,strlen(msg));
if (rv!=1)
{
printf( "Err\n" );
return ;
}
//結束資料加密,把剩餘資料輸出。
rv = EVP_EncryptFinal_ex(ctx, out +outl,&outltmp);
if (rv!=1)
{
printf( "Err\n" );
return ;
}
outl = outl +outltmp;
printf( "原文為:%s\n" ,msg);
//列印輸出密文
printf( "密文長度:%d\n密文資料:\n" ,outl);
for (i=0;i<outl;i++)
{
printf( "0x%02x " , out [i]);
}
printf( "\n" );
}
int main()
{
OpenSSL_add_all_algorithms();
tEVP_Encrypt();
return 0;
}
|
編譯、執行實現:
gcc -o mysm4 mysm4.c -lpthread -lcrypto ./mysm4 執行結果如下
執行命令
1 |
gcc -o mysm4 mysm4.c -lpthread -lcrypto
|
接下來放到雲上試試~
可以發現也成功了!
在windows中重現: