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中所没有的加解密算法,这使开发加解密算法的应用程序更加简便,相对于传统的开发方法是一个有效稳妥的方法。