OpenSSL使用指南 1 介紹OpenSSL是使用非常廣泛的SSL的開源實現(xiàn)。由于其中實現(xiàn)了為SSL所用的各種加密算法,因此OpenSSL也是被廣泛使用的加密函數(shù)庫。 1.1 SSLSSL(Secure Socket Layer)安全協(xié)議是由Netscape公司首先提出,最初用在保護Navigator瀏覽器和Web服務(wù)器之間的HTTP通信(即HTTPS)。后來SSL協(xié)議成為傳輸層安全通信事實上的標準,并被IETF吸收改進為TLS(Transport Layer Security)協(xié)議。 SSL/TLS協(xié)議位于TCP協(xié)議和應(yīng)用層協(xié)議之間,為傳輸雙方提供認證、加密和完整性保護等安全服務(wù)。SSL作為一個協(xié)議框架,通信雙方可以選用合適的對稱算法、公鑰算法、MAC算法等密碼算法實現(xiàn)安全服務(wù)。 1.2 OpenSSLOpenSSL是著名的SSL的開源實現(xiàn),是用C語言實現(xiàn)的。 OpenSSL的前身是SSLeay,一個由Eric Young開發(fā)的SSL的開源實現(xiàn),支持SSLv2/v3和TLSv1。 伴隨著SSL協(xié)議的普及應(yīng)用,OpenSSL被廣泛應(yīng)用在基于TCP/Socket的網(wǎng)絡(luò)程序中,尤其是OpenSSL和Apache相結(jié)合,是很多電子商務(wù)網(wǎng)站服務(wù)器的典型配置。 2 編譯和安裝OpenSSLOpenSSL開放源代碼,這對學(xué)習(xí)、分析SSL和各種密碼算法提供了機會,也便于在上面進一步開發(fā)。 2.1 獲取OpenSSL到OpenSSL的網(wǎng)站即可下載當(dāng)前版本的OpenSSL源代碼壓縮包。 當(dāng)前版本openssl- 在Linux中解壓縮: $tar zxf openssl- 在Windows中可以使用winzip或winrar解壓。 2.2 編譯工具編譯OpenSSL需要Perl和C編譯器。在Windows下如果要用加密算法的匯編代碼實現(xiàn),還需要masm或nasm匯編器。(匯編代碼可以比C代碼顯著提高密碼運算速度) Perl在Windows下推薦使用Active Perl。 C編譯器可以使用gcc。在Windows下可以使用visual C++編譯 匯編器推薦使用nasm。 這些工具所在目錄必須加入到PATH環(huán)境變量中去。 2.3 編譯與安裝步驟查看readme是個好習(xí)慣。從readme了解到需要進一步查看INSTALL和INSTALL.W32文件。 在Windows中: >perl Configure VC-WIN32 >ms\do_nasm(如果不使用匯編代碼實現(xiàn),則可>ms\do_ms) >nmake -f ms\ntdll.mak >cd out32dll >..\ms\test 編譯結(jié)果得到頭文件、鏈接庫、運行庫和openssl.exe工具。頭文件位于./inc32或者./inculde目錄,有一個openssl子目錄,內(nèi)有幾十個.h文件。鏈接庫即./out32dll目錄中的libeay32.lib 和ssleay32.lib,分別是密碼算法相關(guān)的和ssl協(xié)議相關(guān)的。運行庫是./out32dll目錄中的libeay32.dll 和ssleay32.dll,和鏈接庫相對應(yīng)。在./out32dll中還有一個工具openssl.exe,可以直接用來測試性能、產(chǎn)生RSA密鑰、加解密文件,甚至可以用來維護一個測試用的CA。 在Linux中的編譯和安裝步驟較簡單: $./config $make $make test $make install 在Linux下,頭文件、庫文件、工具都已被安裝防盜了合適的位置。庫文件是.a或.so格式。 3 使用Openssl.exe使用OpenSSL.exe(Linux中可執(zhí)行文件名是openssl)可以做很多工作,是一個很好的測試或調(diào)試工具。 3.1 版本和編譯參數(shù)顯示版本和編譯參數(shù): >openssl version –a 3.2 支持的子命令、密碼算法查看支持的子命令: >openssl ? SSL密碼組合列表: >openssl ciphers 3.3 測試密碼算法速度測試所有算法速度: >openssl speed 測試RSA速度: >openssl speed rsa 測試des速度: >openssl speed des 3.4 RSA密鑰操作產(chǎn)生RSA密鑰對: >openssl genrsa –out 1.key 1024 取出RSA公鑰: >openssl rsa –in 1.key –pubout –out 1.pubkey 3.5 加密文件加密文件: >openssl enc –e –rc4 –in 1.key –out 1.key.enc 解密文件: >openssl enc –d –rc4 –in 1.key.enc –out 1.key.dec 3.6 計算Hash值計算文件的MD5值: >openssl md5 < 1.key 計算文件的SHA1值: >openssl sha1 < 1.key 4 算法編程APIOpenSSL中支持眾多的密碼算法,并提供了很好的封裝和接口。密碼算法主要分為如下幾類:對稱算法、公鑰算法、散列算法、隨機數(shù)產(chǎn)生算法等。 OpenSSL的目標是實現(xiàn)安全協(xié)議。其中相關(guān)協(xié)議和標準包括:SSL/TLS、PKCS#1、PCKS#10、X.509、PEM、OCSP等。 4.1 對稱算法接口OpenSSL中實現(xiàn)的對稱算法太多,舉三個例子:DES、AES、RC4。 4.1.1 DESDES加密算法是分組算法。DES的基本操作是把64比特明文在56比特密鑰指引下加密成64比特密文。在實際使用中把密鑰看作64比特可以更方便。 DES(IN,KEY)= OUT 4.1.1.1 DES ECB模式在OpenSSL中ECB操作模式對應(yīng)的函數(shù)是DES_ecb_encrypt(),該函數(shù)把一個8字節(jié)明文分組input加密成為一個8字節(jié)密文分組output。參數(shù)中密鑰結(jié)構(gòu)ks是用函數(shù)DES_set_key()準備好的,而密鑰key是用隨機數(shù)算法產(chǎn)生的64個隨機比特。參數(shù)enc指示是加密還是解密。該函數(shù)每次只加密一個分組,因此用來加密很多數(shù)據(jù)時不方便使用。 void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output, DES_key_schedule *ks,int enc); int DES_set_key(const_DES_cblock *key,DES_key_schedule *schedule); 4.1.1.2 DES CBC模式DES算法CBC操作模式加解密函數(shù)是DES_ncbc_encrypt()。參數(shù)length指示輸入字節(jié)長度。如果長度不是8字節(jié)的倍數(shù),則會被用0填充到8字節(jié)倍數(shù)。因此,輸出可能比length長,而且必然是8字節(jié)的倍數(shù)。 void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc); 4.1.1.3 DES CFB模式DES算法CFB操作模式加解密函數(shù)是DES_cfb_encrypt()。參數(shù)length指示輸入字節(jié)長度。參數(shù)numbits則指示了CFB每次循環(huán)加密多少明文比特,也即密文反饋的比特數(shù)目。ivec是初始向量,被看做第0個密文分組,是不用保密但應(yīng)隨機取值的8個字節(jié)。如果在一次會話中數(shù)次調(diào)用DES_cfb_encrypt(),則應(yīng)該記憶ivec。由于CFB模式中每次DES基本操作只加密numbits比特明文,因此如果numbits太小則效率太低。 void DES_cfb_encrypt(const unsigned char *in, unsigned char *out, int numbits, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc); 另有一個numbit是64比特的版本,既高效又沒有填充的麻煩,推薦使用。num中的返回值指示了ivec中的狀態(tài),是和下次調(diào)用銜接的。 void DES_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, DES_key_schedule *schedule, DES_cblock *ivec, int *num, int enc); 4.1.1.4 DES OFB模式OFB和CFB類似,也有兩個函數(shù),用法一樣。 void DES_ofb_encrypt(const unsigned char *in,unsigned char *out,int numbits,long length,DES_key_schedule *schedule,DES_cblock *ivec); void DES_ofb64_encrypt(const unsigned char *in,unsigned char *out,long length,DES_key_schedule *schedule,DES_cblock *ivec,int *num); 4.1.1.5 DES函數(shù)實例程序4.1.2 AESAES加密算法是分組算法。典型參數(shù)的AES的基本操作是把128比特明文在128比特密鑰指引下加密成128比特密文。 AES(IN,KEY)= OUT OpenSSL中關(guān)于AES的函數(shù)名和參數(shù)接口和DES的雷同。相關(guān)函數(shù)名如下(參數(shù)略)。 int AES_set_encrypt_key(); int AES_set_decrypt_key(); void AES_ecb_encrypt(); void AES_cbc_encrypt(); void AES_cfb128_encrypt(); void AES_ofb128_encrypt(); AES實例程序 4.1.3 RC4RC4密碼算法是流算法,也叫序列算法。流算法是從密鑰作為種子產(chǎn)生密鑰流,明文比特流和密鑰流異或即加密。RC4算法由于算法簡潔,速度極快,密鑰長度可變,而且也沒有填充的麻煩,因此在很多場合值得大力推薦。 OpenSSL中RC4算法有兩個函數(shù): RC4_set_key()設(shè)置密鑰,RC4()加解密??梢园?/span>RC4看作異或,因此加密兩次即解密。 void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data); void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata, unsigned char *outdata); RC4示例程序: #include <stdio.h>
int enc(char* buff, int len, char* buff2, int* len2) memset(passwd, 0, 16); RC4_set_key(&key, 16, passwd); RC4(&key, len, buff, buff2); *len2 = len; return 0; main(int argc, char* argv[]) if (argc!=2) fname1 = argv[1]; while (1) fclose(file1); 4.2 公鑰算法OpenSSL中實現(xiàn)了RSA、DSA、ECDSA等公鑰算法。 4.2.1 RSARSA是分組算法,典型的密鑰模長度1024比特時,分組即是1024比特,即128字節(jié)。 4.2.1.1 RSA密鑰RSA密鑰產(chǎn)生函數(shù)RSA_generate_key(),需要指定模長比特數(shù)bits和公鑰指數(shù)e。另外兩個參數(shù)為NULL即可。 RSA * RSA_generate_key(int bits, unsigned long e, void (*callback) (int,int,void *),void *cb_arg); 如果從文件中讀取密鑰,可使用函數(shù)PEM_read_bio_PrivateKey()/ PEM_read_bio_PUBKEY();EVP_PKEY 中包含一個RSA結(jié)構(gòu),可以引用。 EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); 4.2.1.2 RSA加密解密RSA加密函數(shù)RSA_public_encrypt()使用公鑰部分,解密函數(shù)RSA_private_decrypt()使用私鑰。填充方式常用的有兩種RSA_PKCS1_PADDING和RSA_PKCS1_OAEP_PADDING。出錯時返回-1。輸入必須比RSA鑰模長短至少11個字節(jié)(在RSA_PKCS1_PADDING時?)。輸出長度等于RSA鑰的模長。 int RSA_public_encrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding); int RSA_private_decrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding); 4.2.1.3 簽名和驗證簽名使用私鑰,驗證使用公鑰。RSA簽名是把被簽署消息的散列值編碼后用私鑰加密,因此函數(shù)中參數(shù)type用來指示散列函數(shù)的類型,一般是NID_md5或NID_sha1。正確情況下返回0。 int RSA_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, RSA *rsa); int RSA_verify(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigbuf, unsigned int siglen, RSA *rsa); 4.2.1.4 RSA函數(shù)實例程序4.3 Hash算法Hash算法舉MD5和SHA1兩個例子。Hash算法重復(fù)接收用戶輸入,直到最后一次結(jié)束時輸出散列結(jié)果。 4.3.1MD5MD5算法輸出的散列值是16字節(jié)。 int MD5_Init(MD5_CTX *c); int MD5_Update(MD5_CTX *c, const void *data, size_t len); int MD5_Final(unsigned char *md, MD5_CTX *c); 4.3.2 SHA1SHA1算法輸出的散列值是20字節(jié)。 int SHA1_Init(SHA_CTX *c); int SHA1_Update(SHA_CTX *c, const void *data, size_t len); int SHA1_Final(unsigned char *md, SHA_CTX *c); 4.3.3 MD5例子4.4 隨機數(shù)算法隨機性是密碼安全的基石。為了產(chǎn)生安全的偽隨機數(shù),必須有好的隨機因素作為種子。OpenSSL在內(nèi)部做了努力,但是仍建議在實用隨機數(shù)產(chǎn)生函數(shù)之前添加隨機因素。 函數(shù)RAND_add()可以添加隨機因素到內(nèi)部狀態(tài)中去。然后,即可以使用RAND_bytes()獲得隨機數(shù)。 void RAND_add(const void *buf,int num,double entropy); int RAND_bytes(unsigned char *buf,int num); 5 SSL協(xié)議編程API5.1 客戶端5.2服務(wù)器端5.3 SSL實例程序6 CA和證書6.1 OpenSSL中CA的配置6.2 配置實例6.3 證書解析6.4 解析實例程序7 參考網(wǎng)址SSL 3.0 Specification Transport Layer Security (tls) Charter http://www./html.charters/tls-charter.html OpenSSL: The Open Source toolkit for SSL/TLS SSLeay OpenSSL中文論壇 Perl http://www./Products/ActivePerl/ NASM |
|