關於openssl幾個API的一點小收穫
因為我主要對非對稱加密的RSA演算法比較感興趣,網上最多的就是這麼用的:
生成私鑰檔案(其中已經包含了公鑰):
[[email protected] release]#openssl genrsa -out plainPrv.key 1024 |
然後再從這個私鑰檔案裡將公鑰提取出來,儲存到檔案裡:
[[email protected] release]#openssl rsa -in plainPrv.key -pubout -out plainPub.key |
RSA一般有兩種應用場景:
1、公鑰加密、私鑰解密:這是資料安全通訊領域最常見情形;
2、私鑰加密、公鑰解密:這主要用於數字簽名。
兩種方式,一通百通,本文只看第一種場景。
關於測試程式碼,網上到處都是,也都基本能用,我就先不摘抄了。大家問的最多的問題就是在讀取公鑰檔案時,PEM_read_RSA_PUBKEY()
其實,我們要是看看一兩個檔案內容就明白了:
[[email protected] release]# cat plainPrv.key -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDlGVxzTDVhnC16SW+D0WG8hvm1wztmr0vBh2VK6CU7k90mdrCx 4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBHKttjIx5Diq3wLXDP2qU4mjSI vHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFnicMugj+0sXik1pLWwIwIDAQAB AoGBAKoB5OomfmJ92/2oKxmdsjKN0xY/13++y6/EgrVQifipJG5bm4mVI01F7Ket ai3AuHpWy+DPUy3BndSWFyfAsyatULiK3cJnIZumxmWP8G9odfO1pH/KcZB2Vi61 HcbioDuJRCcF3jpbGMun3lCwkdG/qVfsFmOElbzSbNMDbwkJAkEA/K9mOSKrP+lu 6bsIuD6/n2XQkz8XE2lPuPwKhVLX+ljXqRyxJZH0n+2EC8pUi694Q2Zhgn0uPdEl KCYtlBaLXQJBAOgawH01Xc0r63+XVif6rLZfwJGBAP8921e2dRDFYhYLP3riflY8 xvFQsh4n7kbAXt4xZ3pDA/J1INnE01Rk8X8CQCmzyOslDZ4+qE9qzsWZlYZ5BzNF 9kj92GpvLk1SntJyVyVR1uqcbAL48BICEnH7Q53cB7vBbSBGpBs8Mcl+7wECQQCF Dbjkze/sys2ggd+44WGa1n8sqhgpOYuA1656I7ybyGzmg+pKg2LEOS8yTE+yrVp0 4ztfggVEO1LOo59F1Ov/AkEApfUtgKHB4YCPy70syFaQoAWjiaxOWq/FLM7FBntP ikz1X7gNsRkb4I/be15ZN8E/2Z0Q95FOpsgqw76Bi4Yynw== -----END RSA PRIVATE KEY----- [ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlGVxzTDVhnC16SW+D0WG8hvm1 wztmr0vBh2VK6CU7k90mdrCx4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBH KttjIx5Diq3wLXDP2qU4mjSIvHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFni cMugj+0sXik1pLWwIwIDAQAB -----END PUBLIC KEY----- |
當我們在用PEM_read_RSAPublicKEY()讀取公鑰檔案plainPub.key時報的錯誤是醬紫滴:
3077879432:error:0906D06C:lib(9):func(109):reason(108):pem_lib.c:698:Expecting: RSA PUBLIC KEY |
所以我就天真地將公鑰檔案頭和尾分別改成“-----BEGIN RSA PUBLIC KEY-----”和“-----BEGIN RSA PUBLIC KEY-----”,理想很豐滿,顯示很骨感。實踐證明openssl是不能那麼輕易就被忽悠過去的。沒辦法,檢視openssl原始碼發現,提取公鑰檔案時除了-pubout引數可以設定外,還有有個引數叫做-RSAPublicKey_out,但是命令列提示和man手冊里居然沒有任何提及。幸好我還會讀C程式碼,所以提取公鑰時我改用下面的命令:
[[email protected] release]#openssl rsa -in plainPrv.key -RSAPublicKey_out -out plainPub.key |
這樣做完的結果是,首先公鑰檔案的內容有點變化:
[[email protected] test_openssl]# cat plainPub2.key -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAOUZXHNMNWGcLXpJb4PRYbyG+bXDO2avS8GHZUroJTuT3SZ2sLHhvLVR FxnqJLorGibFKpaYr2DYLSJF3zHHs7LKQEcq22MjHkOKrfAtcM/apTiaNIi8c/cz CCs5HYnBriY2vW94zZzWnJefnEh9mzYgWeJwy6CP7SxeKTWktbAjAgMBAAE= -----END RSA PUBLIC KEY----- [[email protected] release]# cat plainPub.key -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlGVxzTDVhnC16SW+D0WG8hvm1 wztmr0vBh2VK6CU7k90mdrCx4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBH KttjIx5Diq3wLXDP2qU4mjSIvHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFni cMugj+0sXik1pLWwIwIDAQAB -----END PUBLIC KEY----- |
其次,當我再用PEM_read_RSAPublicKEY()介面來讀取公鑰檔案plainPub2.key時,居然成功了。說明RSA PUBLIC KEY和PUBLIC KEY的兩種公鑰檔案其儲存方式是不一樣的,PEM_read_RSAPublicKEY()只能讀取RSA PUBLIC KEY形式的公鑰檔案;而PEM_read_RSA_PUBKEY()只能讀取PUBLIC KEY格式的公鑰檔案。由於本人密碼學基礎較薄弱,現在還不能說出兩者的區別,請各位見諒,還望密碼方面的大牛們予以點撥。演示程式碼如下:
點選(此處)摺疊或開啟
- /* filename: tmp.c
- */
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<string.h>
-
#include<openssl/rsa.h>
-
#include<openssl/pem.h>
-
#include<openssl/err.h>
-
void hexprint(char *str,int len)
-
{
-
int i=0;
-
for(i=0;i<len;i++){
-
printf("%s%02x%s",((i%16==0?"|":"")),*((unsigned char*)str+i),(((i+1)%16==0)?"|\n":" "));
-
}
-
if(i%16!=0)
-
printf("|\n");
-
}
-
static int do_operation(RSA* rsa_ctx,char *instr,char* path_key,int inlen,char** outstr,int type)
-
{
-
if(rsa_ctx == NULL || instr == NULL || path_key == NULL)
-
{
-
perror("input elems error,please check them!");
-
return -1;
-
}
-
int rsa_len,num;
-
rsa_len=RSA_size(rsa_ctx);
-
*outstr=(unsigned char *)malloc(rsa_len+1);
-
memset(*outstr,0,rsa_len+1);
-
switch(type){
-
case 1: //pub enc
-
if(inlen == 0){
-
perror("input str len is zero!");
-
goto err;
-
}
-
num = RSA_public_encrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_OAEP_PADDING);
-
break;
-
case 2: //prv dec
-
num = RSA_private_decrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_OAEP_PADDING);
-
default:
-
break;
-
}
-
if(num == -1)
-
{
-
printf("Got error on enc/dec!\n");
-
err:
-
free(*outstr);
-
*outstr = NULL;
-
num = -1;
-
}
-
return num;
-
}
-
int rsa_pub_encrypt(char *str,char *path_key,char** outstr){
-
RSA *p_rsa;
-
FILE *file;
-
int flen,rsa_len,num;
-
if((file=fopen(path_key,"r"))==NULL){
-
perror("open key file error");
-
return -1;
-
}
-
#ifdef RSAPUBKEY
-
if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
-
#else
-
if((p_rsa=PEM_read_RSAPublicKey(file,NULL,NULL,NULL))==NULL){
-
#endif
-
ERR_print_errors_fp(stdout);
-
return -1;
-
}
-
num = do_operation(p_rsa,str,path_key,strlen(str),outstr,1);
-
RSA_free(p_rsa);
-
fclose(file);
-
return num;
-
}
-
int rsa_prv_decrypt(char *str,char *path_key,int inlen,char** outstr){
-
RSA *p_rsa;
-
FILE *file;
-
int rsa_len,num;
-
if((file=fopen(path_key,"r"))==NULL){
-
perror("open key file error");
-
return -1;
-
}
-
if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
-
ERR_print_errors_fp(stdout);
-
return -1;
-
}
-
num = do_operation(p_rsa,str,path_key,inlen,outstr,2);
-
RSA_free(p_rsa);
-
fclose(file);
-
return num;
-
}
-
int main(int argc,char** argv){
-
char *ptr_en,*ptr_de;
-
int len;
-
printf("source is :%s\n",argv[1]);
-
len=rsa_pub_encrypt(argv[1],argv[2],&ptr_en);
-
printf("pubkey encrypt:\n");
-
hexprint(ptr_en,len);
-
rsa_prv_decrypt(ptr_en,argv[3],len,&ptr_de);
-
printf("prvkey decrypt:%s\n",ptr_de==NULL?"NULL":ptr_de);
-
if(ptr_en!=NULL){
-
free(ptr_en);
-
}
-
if(ptr_de!=NULL){
-
free(ptr_de);
-
}
-
return 0;
- }
如果開啟RSAPUBKEY巨集,則用PEM_read_RSA_PUBKEY()來讀取公鑰檔案;否則用PEM_read_RSAPublicKey()讀取:
[[email protected] release]#gcc -o pub rsatest.c -lcrypto -g -DRSAPUBKEY [[email protected] release]#gcc -o nopub rsatest.c -lcrypto -g |
測試結果如下:
實際應用中,出於安全考慮我們一般會對私鑰檔案加密。我們可以用如下的方式來重新生成經3DES加密後私鑰檔案:
[[email protected] release]#openssl genrsa -des3 -out cipherPrv.key 1024 |
這樣生成的私鑰檔案使用3DES加過密的,看看內容就曉得和之前的有什麼不同了。頭部多了一些資訊:Proc-Type和DEK-Info,猜想這肯定是某種加密資訊(這TM不廢話麼),但是我看不懂,現階段“會用”是首要問題:
上述加密私鑰檔案的口令是123456,分別提取RSA PUBLIC KEY和PUBLIC KEY格式的公鑰檔案:
[[email protected] release]# openssl rsa -in cipherPrv.key -pubout -out cipherPub.key [[email protected] release]# openssl rsa -in cipherPrv.key -RSAPublicKey_out -out cipherPub2.key |
在程式碼中我們需要通過下面的方式來讀取經3DES加密處理後的私鑰檔案:
點選(此處)摺疊或開啟
-
RSA* getPRV(char *path_key_fullname,char* pwd)
-
{
-
RSA *rsaK=RSA_new();
-
OpenSSL_add_all_algorithms();
-
BIO *BP = BIO_new_file(path_key_fullname,"rb");
-
if(NULL == BP)
-
return NULL;
- rsaK=PEM_read_bio_RSAPrivateKey(BP,NULL,NULL,pwd);
-
return rsaK;
- }
if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
替換成:
if((p_rsa=getPRV(path_key,"123456"))==NULL){
重新編譯,執行後結果如下:
關於openssl有很多值得學習的地方,空了再慢慢研究。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 閱讀(14329) | 評論(2) | 轉發(2) | 給主人留下些什麼吧!~~
2015-12-23 14:05:21
太感謝了,解決了大問題。PEM_read_RSA_PUBKEY 不知道這個地方為什麼這麼用,有啥研究成果木有
回覆 | 舉報2014-11-25 17:05:41
太棒了,謝謝分享~
回覆 | 舉報 評論熱議相關推薦
關於openssl幾個API的一點小收穫
今天心血來潮突然想搞搞openssl了,趁著端午小假,剛好有空可以鼓搗孤島自己喜歡的東西,出去東奔西跑的實在太造孽了,還是宅起來給自己充充電吧。下載openssl最新程式碼1.0.1g,修復了“心血漏洞”那個版本。編譯安裝那些小兒科的東西就不再浪費筆墨了,如果出現標頭
【Linux】linux常用幾個基本命令 小白專區簡單易懂
ls -l 17. 命令補全 linu 刪除目錄 poweroff 環境 密碼 family 顯示日期的命令 date顯示日歷的命令 cal -s, --hctosys以硬件時鐘為準,校正系統時鐘hwclock,clock:顯示硬件時鐘 -w, --sy
使用Formik輕松開發更高質量的React表單(四)其他幾個API解析
else errors method however obj disable user etc gree (下面部分內容正處於翻譯中,敬請稍等......) <Field /> <Field /> will automagically hook up
實現毫秒級和納秒級計數的幾個API--timeGetTime、GetTickCount、QueryPerformanceCounter
Private Declare Function timeGetTime Lib "winmm.dll" () As Long Private Declare Function GetTickCount Lib "kernel32" () As Long Private Declar
JavaWeb基礎總結之Js幾個經典的小案例
(1)動態顯示當前系統時間 <body> <p>當前時間:<span id="times"></span></p> </body> <script> function get(){
深入 TypeScript - 2( 幾個常用的小技巧)
寫在最前面 剛開始寫 typescript 遇到的問題和簡單的解決方案。 Q&A 1、是否所有變數都需要做型別註解? 這個分情況,原則上來說,我們希望能對所有的值都做型別註解。 對於TS編譯器來說,如果宣告變數時沒有做型別註解,那麼TS會根據賦值自動推匯出變數型別。這
測試中幾個實用的小工具
1 身份證號碼生成器 我是做p2p理財業務的,測試中會用到身份證。自己編的話太隨意,有時候還無法通過一些規則 身份證號碼和姓名_身份證號碼和真實姓名大全_身份證號碼大全防沉迷_身份證號碼查詢sfz.ckd.cc 2密碼生成器 公司用阿里雲,阿里雲的密碼我一般就隨機生成,可以設定你要的規則,生成符合規
source insight下幾個實用的小工具
1、SourceMonitor使用 C語言度量值(C Metrics)、 總函式(Lines):包括空行在內的程式碼行數; 語句數目(Statements):在C語言中語句就是以分號結尾的。分支語句IF,迴圈語句FOR,跳轉語句都被計算在內,預處理語句#include
胡八一之Java(六):表示式的幾個簡單的小陷阱
1、複合賦值運算子的陷阱 a=a+5與a +=5 是有區別的。a +=5等價於 a=(a的型別)(a+5);這就是複合運算子中包含的隱式型別轉換。 在什麼時候會遇到此型別的錯誤呢? short a =5; a = (a-2); 此句編譯不通過,把一個int
yum源使用的幾個報錯小總結
伺服器上的yum突然不好使用,使用yum時有如下幾個保持,解決方案如下: 1)Error: Cannot retrieve repository metadata (repomd.xml) for repository: rpmforge. [[email protected] src
關於CString的一點小收穫,CString在控制檯程式中輸出到螢幕
CString是一個非常好用的類,這就不用多說了,但是由於只能在MFC中使用,使得他的使用變得非常有限。筆者通過上網研究和親自實踐發現在控制檯程式中也可以輕鬆使用CString。 首先,要在控制檯中使用CString必須要加入標頭檔案 #include <atlst
使用者行為分析需要知道的幾個埋點小技巧
使用者行為分析系統是指由第三方提供的集合了資料採集SDK、資料分析模型、分散式演算法與儲存架構的使用者屬性與行為事件資料分析的系統。比如國外MixPanel、Heap等,使用者行為資料分析的前提是在前期埋點時打好紮實的基礎。 事件觸發的條件、需要追蹤的屬性以及想要分析的
初識PLSQL 幾個簡單的小程式
1.順序程式程式碼 declare V_counter number:=1; begin loop dbms_output.put_line('V_counter當前的值為
剛接觸SkyLine的一點小收穫與感觸
因為剛接觸Skyline不到一個星期,也怕把學習到的忘記掉,所以寫一點學習到的一些皮毛的東西,趕緊記錄一下,怕回頭忘記 1.網上關於web端的開發非常多,也有很多牛人分享自己的經驗,所以學習起來也相對更便捷 2.關於外掛的開發,網上基本上沒有,我也只找到一個是用C#做的,顯然和Skyline的html外掛
新手學Python必看的幾個練手小專案,輕鬆不枯燥哦!
Python是一種面向物件的解釋型程式語言,原始碼與直譯器CPython遵守GPL協議,Python語法簡潔清晰。 語法簡潔清晰,那麼我們用少量的Python程式碼能做哪些有趣的東西?溫馨提示:文末必看。 一、畫愛心表白 1、圖形都是由一系列的點(X,Y)構成的曲線,由於X
爬蟲-幾個簡單的小檔案
本週第一次接觸爬蟲,在https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html上簡單入門後便在馬神的指導下寫了一些簡單的爬蟲。 因為以前web,html,css,xpath都沒有接觸過
112. 路徑總和(樹遞迴中的一點小收穫_什麼是子節點)
給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定如下二叉樹,以及目標和 sum = 22, 5.
[Termux] 幾個有意思的小軟體包
因式分解小軟體 pkg install coreutils 然後使用 factor number命令呼叫 如:factor 200 反饋:200: 2 2 2 5 5 Figlet 簡單方便地用符號畫出英文字母 | 不支援中文 ap
幾個精妙的小問題(By Divide and Conquer)
所謂分治法就是分而治之的意思,即將一個不易解決的大問題分解為幾個易於解決的小問題,然後再將各個小問題的解合併起來就是大問題的解。這種方法雖然簡單,但是對於很多問題都很有效,下面試舉幾例: 問題一:有效字串個數問題能在通道上傳遞的字串滿足如下兩條性質:該字串中只包含'a'、
幾個有意思的小程式,當無限迴圈遇到sleep會發生什麼 !!!∑(゚Д゚ノ)ノ
今天翻文件的時候找到了幾個剛學Java的時候的小程式,跟大家共享一個,其他點 這裡 下載(下載連線包含所有展示的程式,如果實在沒幣可以私聊我,我給你發一份,有幣就支援一下把,謝謝) 這是倒數第二個的程式碼,非常簡單,矩陣的那個複雜一些,但是更有意思,點 這裡下載(下載連線包