1. 程式人生 > >openssl 使用指南 (轉)

openssl 使用指南 (轉)

•  介紹

•  編譯

•  執行 OpenSSL.exe

•  演算法程式設計 API

•  介紹

OpenSSL 是使用非常廣泛的 SSL 的開源實現。由於其中實現了為 SSL 所用的各種加密演算法,因此 OpenSSL 也是被廣泛使用的加密函式庫。

1.1 SSL

SSL(Secure Socket Layer) 安全協議是由 Netscape 公司首先提出,最初用在保護 Navigator 瀏覽器和 Web 伺服器之間的 HTTP 通訊 ( 即 HTTPS) 。後來 SSL 協議成為傳輸層安全通訊事實上的標準,並被 IETF 吸收改進為 TLS(Transport Layer Security) 協議。 SSL/TLS 協議位於 TCP 協議和應用層協議之間,為傳輸雙方提供認證、加密和完整性保護等安全服務。 SSL 作為一個協議框架,通訊雙方可以選用合適的對稱演算法、公鑰演算法、 MAC 演算法等密碼演算法實現安全服務。

1.2 OpenSSL

OpenSSL 是著名的 SSL 的開源實現,是用 C 語言實現的。

OpenSSL 的前身是 SSLeay ,一個由 Eric Young 開發的 SSL 的開源實現,支援 SSLv2/v3 和 TLSv1 。

伴隨著 SSL 協議的普及應用, OpenSSL 被廣泛應用在基於 TCP/Socket 的網路程式中,尤其是 OpenSSL 和 Apache 相結合,是很多電子商務網站伺服器的典型配置。

•  編譯和安裝 OpenSSL

OpenSSL 開放原始碼,這對學習、分析 SSL 和各種密碼演算法提供了機會,也便於在上面進一步開發。

2.1 獲得 OpenSSL

到 OpenSSL 的網站 http://www.openssl.org/source/ 即可下載當前版本的 OpenSSL 原始碼壓縮包。 當前版本 openssl- 1.0.0 beta3 。其中 crypto 子目錄中是眾多密碼演算法實現 ssl 子目錄中是 SSL 協議的實現。

Linux 中解壓縮:

$tar zxf openssl-1.0.0-beta3.tar.gz, 在 Windows 中可以使用 winzip 或 winrar 。

2.2 編譯工具

編譯 OpenSSL 需要 Perl 和 C 編譯器。在 Windows 下如果要用加密演算法的彙編程式碼實現,還需要 masm 或 nasm 彙編器

。 ( 彙編程式碼可以比 C 程式碼顯著提高密碼運算速度 )

Perl 在 Windows 下推薦使用 Active Perl 。

C 編譯器可以使用 gcc 。在 W indows 下可以使用 Visual C 編譯器。

彙編器推薦使用 nasm 。

這些工具所在目錄必須加入到 PATH 環境變數中去

2.3 編譯和安裝步驟

檢視 readme 是個好習慣。從 readme 瞭解到需要進一步檢視 INSTALL 和 INSTALL.W32 檔案。

在 Windows 中:

>perl Configure VC-WIN32

>ms"do_nasm ( 如果不使用匯編程式碼實現,則可 >ms"do_ms)

>nmake -f ms"ntdll.mak

>cd out32dll

>.."ms"test

編譯結果得到標頭檔案、連結庫、執行庫和 openssl.exe 工具

標頭檔案位於 ./inc32 或者 ./inculde 目錄,

有一個 openssl 子目錄,內有幾十個 .h 檔案。

連結庫即 ./out32dll 目錄中的 libeay32.lib 和 ssleay32.lib ,分別是密碼演算法相關的和 ssl 協議相關的。

執行庫是 ./out32dll 目錄中的 libeay32.dll 和 ssleay32.dll ,和連結庫相對應。

在 ./out32dll 中還有一個工具 openssl.exe ,可以直接用來測試效能、產生 RSA 金鑰、加解密檔案,甚至可以用來維護一個測試用的 CA 。

在 Linux 中的編譯和安裝步驟較簡單 :

$./config

$make

$make test

$make install

在 Linux 下,標頭檔案、庫檔案、工具都已被安裝放到了合適的位置。庫檔案是 .a 或 .so 格式。

•  使用 OpenSSL.exe

使用 OpenSSL.exe(Linux 中可執行檔名是 openssl) 可以做很多工作,是一個很好的測試或除錯工具。

3.1 版本和編譯引數

顯示版本和編譯引數: >openssl version -a

3.2 支援的子命令、密碼演算法

檢視支援的子命令: >openssl ?

SSL 密碼組合列表: >openssl ciphers

3.3 測試密碼演算法速度

測試所有演算法速度: >openssl speed

測試 RSA 速度: >openssl speed rsa

測試 DES 速度: >openssl speed des

3.4 RSA 金鑰操作

產生 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

•  演算法程式設計 API

OpenSSL 中支援眾多的密碼演算法,並提供了很好的封裝和介面。密碼演算法主要分為如下幾類:對稱演算法、公鑰演算法、雜湊演算法、隨機數產生演算法等。

OpenSSL 的目標是實現安全協議。其中相關協議和標準包括: SSL/TLS 、 PKCS#1 、 PCKS#10 、 X.509 、 PEM 、 OCSP 等

4.1 對稱演算法介面

OpenSSL 中實現的對稱演算法太多,舉三個例子: DES 、 AES 、 RC4 。

4.1.1 DES

DES 加密演算法是分組演算法。 DES 的基本操作是把 64 位元明文在 56 位元金鑰指引下加密成 64 位元密文。在實際使用中把金鑰看作 64 位元可以更方便。

DES ( IN , KEY ) = OUT

(1) DES ECB 模式

在 OpenSSL 中 ECB 操作模式對應的函式是 DES_ecb_encrypt() ,該函式把一個 8 位元組明文分組 input 加密成為一個 8 位元組密文分組 output 。引數中金鑰結構 ks 是用函式 DES_set_key() 準備好的,而金鑰 key 是用隨機數演算法產生的 64 個隨機位元。引數 enc 指示是加密還是解密。該函式每次只加密一個分組,因此用來加密很多資料時不方便使用。

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);

(2) DES CBC 模式

DES 演算法 CBC 操作模式加解密函式是 DES_ncbc_encrypt() 。引數 length 指示輸入位元組長度。如果長度不是 8 位元組的倍數,則會被用 0 填充到 8 位元組倍數。因此,輸出可能比 length 長,而且必然是 8 位元組的倍數。

void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc);

(3) DES CFB 模式

DES 演算法 CFB 操作模式加解密函式是 DES_cfb_encrypt() 。引數 length 指示輸入位元組長度。引數 numbits 則指示了 CFB 每次迴圈加密多少明文位元,也即密文反饋的位元數目。 ivec 是初始向量,被看做第 0 個密文分組,是不用保密但應隨機取值的 8 個位元組。如果在一次會話中數次呼叫 DES_cfb_encrypt() ,則應該記憶 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 中的狀態,是和下次呼叫銜接的。

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) DES OFB 模式

OFB 和 CFB 類似,也有兩個函式,用法一樣。

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);

(5) DES 函式示例程式

見附件 A.1 。

4.1.2 AES

AES 加密演算法是分組演算法。典型引數的 AES 的基本操作是把 128 位元明文在 128 位元金鑰指引下加密成 128 位元密文。

AES ( IN , KEY ) = OUT

OpenSSL 中關於 AES 的函式名和引數介面和 DES 的雷同。相關函式名如下 ( 引數略 ) 。

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 示例程式見附件 A.2 。

4.1.3 RC4

RC4 密碼演算法是流演算法,也叫序列演算法。流演算法是從金鑰作為種子產生金鑰流,明文位元流和金鑰流異或即加密。 RC4 演算法由於演算法簡潔,速度極快,金鑰長度可變,而且也沒有填充的麻煩,因此在很多場合值得大力推薦。

OpenSSL 中 RC4 演算法有兩個函式 : RC4_set_key() 設定金鑰, RC4() 加解密。可以把 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 示例程式見附件 A.3 。

例子 A.3.(1) 是利用 OpenSSL 動態庫函式。例子 A.3.(2) 是把 RC4 的實現程式碼從 OpenSSL 中分離出來的。例子 A.3.(3) 是另一個演示實現。

4.2 公鑰演算法

OpenSSL 中實現了 RSA 、 DSA 、 ECDSA 等公鑰演算法

4.2.1 RSA

RSA 是分組演算法,典型的金鑰模長度 1024 位元時,分組即是 1024 位元,即 128 位元組。

(1) RSA 金鑰

RSA 金鑰產生函式 RSA_generate_key() ,需要指定模長位元數 bits 和公鑰指數 e 。另外兩個引數為 NULL 即可。

RSA * RSA_generate_key(int bits, unsigned long e, void (*callback) (int,int,void *),void *cb_arg);

如果從檔案中讀取金鑰,可使用函式 PEM_read_bio_PrivateKey()/ PEM_read_bio_PUBKEY(); EVP_PKEY 中包含一個 RSA 結構,可以引用。

EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);

(2) RSA 加密解密

RSA 加密函式 RSA_public_encrypt() 使用公鑰部分,解密函式 RSA_private_decrypt() 使用私鑰。填充方式常用的有兩種 RSA_PKCS1_PADDING 和 RSA_PKCS1_OAEP_PADDING 。出錯時返回 -1 。輸入必須比 RSA 鑰模長短至少 11 個位元組(在 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);

(3) 簽名和驗證

簽名使用私鑰,驗證使用公鑰。 RSA 簽名是把被簽署訊息的雜湊值編碼後用私鑰加密,因此函式中引數 type 用來指示雜湊函式的型別,一般是 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) RSA 函式示例程式

RSA 示例程式見附件 A.4 。

例子 A.4.(1) 是加密解密例子。例子 A.4.(2) 是簽名驗證例子。

4.2.2 DSA

( TOBE )

4.2.2 ECDSA

( or NOT TOBE )

4.3 Hash 演算法

Hash 演算法舉 MD5 和 SHA1 兩個例子。 Hash 演算法重複接收使用者輸入,直到最後一次結束時輸出雜湊結果。

4.3.1 MD5

MD5 演算法輸出的雜湊值是 16 位元組。

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 SHA1

SHA1 演算法輸出的雜湊值是 20 位元組。

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 例子

MD5 示例程式見附件 A.5 。

md5sum 這是一個實用小工具,可以計算一個檔案的 MD5 值。

4.4 隨機數演算法

隨機性是密碼安全的基石。為了產生安全的偽隨機數,必須有好的隨機因素作為種子。 OpenSSL 在內部做了努力,但是仍建議在實用隨機數產生函式之前新增隨機因素。

函式 RAND_add() 可以新增隨機因素到內部狀態中去。然後,即可以使用 RAND_bytes() 獲得隨機數。

void RAND_add(const void *buf,int num,double entropy);

int RAND_bytes(unsigned char *buf,int num);

•  參考網址

SSL 3.0 Specification

Transp ort Layer Security (tls) Charter

OpenSSL: The Open Source toolkit for SSL/TLS

SSLeay

OpenSSL 中文論壇

Perl

NASM