1. 概念
OpenSSL項目是一個開放源代碼安全項目,它的目標是開發一個健壯的、商業級的、完整的開放源代碼的工具包,用強大的加密算法來實現安全的Socket層(Secure Sockets Layer,SSL v2/v3)和傳輸層的安全性(Transport Layer Security,TLS v1)。它包含了完整的加密算法,數字簽名算法及證書算法等。可以很好地保證數據的完整,保密和正確性。OpenSSL可以和於商業用途,但是使用者應該考慮自己所使用的算法有沒有受到本國專利的限制以及考慮是否符合國家制定的標準。
Engine機制 Engine機制的出現是在OpenSSL的0.9.6版的事情,開始的時候是將普通版本跟支持Engine的版本分開的,到了OpenSSL的0.9.7版,Engine機制集成到了OpenSSL的內核中,成爲了OpenSSL不可缺少的一部分。
Engine機制目的是爲了使OpenSSL能夠透明地使用第三方提供的軟件加密庫或者硬件加密設備進行加密。OpenSSL的Engine機制成功地達到了這個目的,這使得OpenSSL已經不僅僅使一個加密庫,而是提供了一個通用地加密接口,能夠與絕大部分加密庫或者加密設備協調工作。當然,要使特定加密庫或加密設備更OpenSSL協調工作,需要寫少量的接口代碼,但是這樣的工作量並不大,雖然還是需要一點密碼學的知識。Engine機制的功能跟Windows提供的CSP功能目標是基本相同的。
目前,OpenSSL的0.9.7版本支持的內嵌第三方加密設備有8種,包括:CryptoSwift、nCipher、Atalla、Nuron、UBSEC、Aep、SureWare以及IBM 4758 CCA的硬件加密設備。現在還出現了支持PKCS#11接口的Engine接口,支持微軟CryptoAPI的接口也有人進行開發。當然,所有上述Engine接口支持不一定很全面,比如,可能支持其中一兩種公開密鑰算法。表1是OpenSSL-0.9.7版本支持的硬件及其對應的簡要描述名稱,這個簡要描述名稱在很多時候是要使用的,如編程或執行命令的時候,簡要密鑰名稱是大小寫敏感的,目前一般都是採用小寫字符。
OpenSSL支持的Engine接口
簡要名稱 |
Engine接口描述 |
dynamic |
動態加載Engine設備的接口 |
cswift |
CryptoSwift的硬件加密設備Engine支持 |
chil |
nChipher硬件加密設備Engine支持 |
atalla |
Atalla硬件加密設備Engine支持 |
nuron |
Nuron硬件加密設備Engine支持 |
ubsec |
UBSEC硬件加密設備Engine支持 |
aep |
Aep硬件加密設備Engine支持 |
sureware |
SureWare硬件加密設備Engine支持 |
4758cca |
IBM 4758 CCA硬件加密設備Engine支持 |
2. 實現
ENGINE是OPENSSL預留的用以加載第三方加密庫引擎,主要包括了動態庫加載的代碼和加密函數指針管理的一系列接口。如果要使用Engine(假設你已經加載上該Engine了),那麼首先要加載該Engine(比如ENGINE_load_XXXX),然後選擇要使用的算法或者使用支持的所有加密算法(有相關函數)。這樣你的應用程序在調用加解密算法時,它就會指向你加載的動態庫裏的加解密算法,而不是原先的OPENSSL的庫裏的加解密算法。
上面提到的一些engine的實現在 openssl/crypto/engine/目錄下可以找到,來分析一下具體的實現:
首先,每一個ENGINE_load_XXXX其實就是一個Engine的加載過程:
如:
void
ENGINE_load_rtl8651b(void)
{
ENGINE *engine = ENGINE_new();
if (engine == NULL)
return;
if (!ENGINE_set_id(engine, "rtl8651b") ||
!ENGINE_set_name(engine, "BSD rtl8651b engine") ||
!ENGINE_set_ciphers(engine, rtl8651b_engine_ciphers)||
!ENGINE_set_digests(engine, rtl8651b_engine_digests)||
!ENGINE_set_ctrl_function(engine, rtl8651b_ctrl) ||
!ENGINE_set_cmd_defns(engine, rtl8651b_defns)
){
ENGINE_free(engine);
return;
}
if(!ENGINE_set_default(engine, ENGINE_METHOD_DIGESTS) )
ENGINE_add(engine);
ENGINE_free(engine);
ERR_clear_error();
}
類似ENGINE_set_xxxx的函數是對engine機制各個方面的設定註冊,有下面這些:
int ENGINE_set_id(ENGINE *e, const char *id);
int ENGINE_set_name(ENGINE *e, const char *name);
int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth);
int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth);
int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth);
int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth);
int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f);
int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f);
int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f);
int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f);
int ENGINE_set_load_privkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpriv_f);
int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f);
int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f);
int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f);
int ENGINE_set_flags(ENGINE *e, int flags);
int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns);
由此可知,具體的(RSA,DSA,DH,RAND,CHIPHERS,DIGESTS)算法實現主要是這些函數實現的。
以DIGESTS爲例:首先要聲明一個對應的數據結構(MD5):
const EVP_MD rtl8651b_hash_md5={
NID_md5,
NID_md5WithRSAEncryption,
MD5_DIGEST_LENGTH,
NULL,
rtl8651b_digest_init,
rtl8651b_digest_update,
rtl8651b_digest_final,
NULL,
NULL,
EVP_PKEY_RSA_method,
MD5_CBLOCK,
sizeof(RTL_DIGEST_CTX)/* how big does the ctx->md_data need to be */
};
具體的各項的含義,請參考EVP_MD數據結構。
這裏rtl8651b_digest_init, rtl8651b_digest_update, rtl8651b_digest_final,就是具體的算法實現。
如果都完成了,則可以調用動態庫中的ENGINE_load_XXXX(例子中是ENGINE_load_ rtl8651b),把ENGINE對象加載到系統中,即在ENGINE對象和DIGESTS的結構裏的ENGINE對象建立了一個關聯,使用這種方法,使ENGINE能夠智能的判斷是使用自定義的加解密算法,還是使用默認的加解密算法。
ENGINE_load_ rtl8651b中,我們可以使用下面的方法來使用你所定義的算法。
ENGINE_set_default(ENGINE *e, int Flag)
其中Flag的說明如下:
ENGINE_METHOD_ALL 使用所有存在的算法(默認)
ENGINE_METHOD_RSA 僅使用RSA算法
ENGINE_METHOD_DSA 僅使用DSA算法
ENGINE_METHOD_DH 僅使用DH算法
ENGINE_METHOD_RAND 僅使用隨機數算法
ENGINE_METHOD_CIPHERS 僅使用對稱加解密算法
ENGINE_METHOD_DIGESTS 僅使用摘要算法
ENGINE_set_default(engine, ENGINE_METHOD_DIGESTS)
上面給出使用ENGINE有效替換OPENSSL中現有的所有的加密算法,使用這個特性也可以很好的加入一些OPENSSL中所沒有的加解密算法,這使開發加解密算法的應用程序更加簡便,相對於傳統的開發方法是一個有效穩妥的方法。