原文連接: http://blog.chinaunix.net/uid-16515626-id-2741894.htmlhtml
因爲項目須要,我計劃利用openssl開發一個基本的CA,實現證書的發放等功能。在項目模型中公私鑰對是用戶本身產生的,而且以16進制數的形似提交給CA。咱們知道,一般利用openssl頒發證書時,公私鑰對每每也是由openssl產生的,好比利用如下三個函數
RSA_generate_key
EVP_PKEY_assign_RSA
X509_set_pubkey
即可以輕鬆搞定從密鑰產生到載入證書的過程,而提取證書公鑰只需
X509_get_pubkey
如何將16進制形式的rsa公鑰載證書的卻沒有相關介紹,通過幾天的研究終於搞定了,貼出來與你們分享,咱們能夠利用下面的函數
RSA* d2i_RSAPublicKey(NULL,(const unsigned **) pp,int len)
其中*pp指向存儲公鑰的內存單元,len指公鑰的長度,請注意這裏的公鑰是指通過ASN.1編碼的公鑰,關於此編碼方法,要想全面闡述是至關複雜的,但若是僅限於編rsa公鑰,則會簡單不少,如下是1024位rsa公鑰的ASN.1編碼的十六進制描述,共佔據140bytes:
30 81 89 02 81 81 00 e3 8d 99 06 9f bd 9a c0 e5
6a 5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0
89 44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f
bc d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad
d4 36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0
37 06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99
54 29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86
14 38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89
4a ae e1 9d 57 3e a1 02 03 01 00 01
ASN.1採用Tag,Lenth,Value,編碼方式,在此將整個編爲一個sequence,能夠理解爲結構體,以30做爲開始標誌,第二位81表明後面有1字節表明長度,即89表明長度(若爲82則表明後面有兩字節表明長度,依次類推),轉化成十進制爲137,正好與後面的字節數吻合,從第四位02開始即是此sequence的內涵,至關於結構體的元素,通常來講sequence每每須要嵌套,至關於結構體嵌結構體,但對公鑰的sequence來講,此處僅有一層。
第四位02表明一下的內容爲bit流,一樣緊隨其後的81表明有一字節表明長度,第六位的81表明長度爲129,即從00開始直到最後一行a1此爲129字節,去掉前面的00,餘下128位即是rsa公鑰的N值,最後5個字節一樣是bit流,以02開始,03表示長度爲3,最後的01 00 01 即是rsa公鑰的E值。
關於爲何要在N值前補00,這多是ASN.1的規定,若bit流的前四bit十六進制值小於8就要在在最前補零,看下面的例子
30 81 88 02 81 80 32 8d 99 06 9f bd 9a c0 e5 6a
5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0 89
44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f bc
d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad d4
36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0 37
06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99 54
29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86 14
38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89 4a
ae e1 9d 57 3e a1 02 03 01 00 01
N的前四bit爲0x3小於8,所以無需補零。
關於什麼狀況下要在tag值以後用8X標明有幾位表明length,個人理解是,若是length的前四bit大於8或超過一字節,則必需用8X標明,不然不用。
言規正傳,瞭解了rsa公鑰的編碼規則,咱們即可以方便的將用其餘工具產生的rsa公鑰編爲openssl可接受的碼型,從而完成公鑰的導入,對於公鑰的提取,一樣有函數
int i2d_RSAPublicKey(RSA *,(const char **))
返回值爲公鑰的長度,固然是經ASN.1編碼後的。
完成了bit流與RSA的轉化,剩下的工做便有很輕鬆了,在此在介紹幾種簡便方法,能夠直接在bit與EVP_PKEY之間轉化:
導出:
len=i2d_RSAPublicKey(pkey->pkey.rsa,(const char**)pp);
導入要多幾步:
pkey->save_type=6;
pkey->type=EVP_PKEY_type(6);
pkey->pkey.rsa=d2i_RSAPublicKey(NULL,(const char**)pp,len);
其中pkey的定義爲EVP_PKEY *pkey;
導入過程當中前兩行的做用是設定採用的密碼算法爲rsa,若採用bit-〉rsa-〉pkey模式,這個工做由EVP_PKEY_assign_RSA替咱們作了。
我接觸openssl4個月了,以上個人經驗總結,歡迎你們批評指正。