openssl engine 实现SM4 引擎
一 openssl engine基本介绍
Engine机制目的是为了使OpenSSL能够透明地使用第三方提供的软件加密库或者硬件加密设备进行加密。OpenSSL的Engine机制成功地达到了这个目的,这使得OpenSSL已经不仅仅使一个加密库,而是提供了一个通用地加密接口,能够与绝大部分加密库或者加密设备协调工作。当然,要使特定加密库或加密设备更OpenSSL协调工作,需要写少量的接口代码,但是这样的工作量并不大。
二 SM4引擎实现
1 Openssl定义好的主接口
IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()
2 定义bind函数
bind函数的定义如下所示:
static int bind(ENGINE *e, const char *id)
{
int ret = 0;
if (!ENGINE_set_id(e, engine_id)) {
fprintf(stderr, "ENGINE_set_id failed\n");
goto end;
}
if (!ENGINE_set_name(e, engine_name)) {
printf("ENGINE_set_name failed\n");
goto end;
}
if (!ENGINE_set_ciphers(e, ciphers)) {
printf("ENGINE_set_name failed\n");
goto end;
}
ret = 1;
end:
return ret;
}
其中主要是使用openssl的引擎API注册和设置sm4引擎,
3 实现ciphers函数
ciphers函数是配置算法结构初始化函数,其定义如下所示:
static int ciphers(ENGINE *e, const EVP_CIPHER **cipher,
const int **nids, int nid)
{
int ok = 1;
#if 1
if (!cipher) {
/* We are returning a list of supported nids */
*nids = sm4_nids;
return (sizeof(sm4_nids) - 1) / sizeof(sm4_nids[0]);
}
#endif
switch (nid) {
case NID_aes_128_ecb:
*cipher = &cipher_sm4;
break;
default:
ok = 0;
*cipher = NULL;
break;
}
return ok;
}
4 定义算法结构evp_cipher_st
定义如下
struct evp_cipher_st cipher_sm4 =
{
NID_aes_128_ecb,//int nid;
16,//int block_size;
16,//int key_len; /* Default value for variable length ciphers */
16,//int iv_len;
0,//unsigned long flags; /* Various flags */
sm4_init,//int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key,
// const unsigned char *iv, int enc); /* init key */
sm4_func,//int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out,
// const unsigned char *in, size_t inl);/* encrypt/decrypt data */
NULL,//int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
sizeof(sm4_ctx_t),//int ctx_size; /* how big ctx->cipher_data needs to be */
NULL,//int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */
NULL,//int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */
NULL,//int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */
NULL,//void *app_data; /* Application data */
} /* EVP_CIPHER */;
在算法结构中,定义了如下信息
(1)指明了算法ID,由于我使用的openssl是1.0版本,还不支持sm4算法,目前只能使用aes的id来代替。
(2) 定义了key和iv的长度,都为16字节
(3)定义了sm4_init 函数,用于初始化sm4算法,包括key 和id。
(4) 定义了sm4_func函数,用于sm4算法的加解密的实现。
(5) 定义了sm4_ctx_t 结构的大小,这个结构体中包括了sm4密钥和加解密标志。
(6)其他没有用到的元素都置NULL
5 实现sm4_init 函数体
int sm4_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
sm4_ctx_t *sm4_contex;
sm4_contex=(sm4_ctx_t *)(ctx->cipher_data);
memcpy(sm4_contex->key,key,16);
sm4_contex->enc_dec=enc;
dump_hex("sm4_init get key",sm4_contex->key,16);
printf("get enc flag: %d\n",sm4_contex->enc_dec);
}
6 实现sm4_func 函数体
int sm4_func(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
sm4_ctx_t *sm4_contex;
sm4_contex=(sm4_ctx_t *)(ctx->cipher_data);
if(sm4_contex->enc_dec)
{
dump_hex("plain data:",in,16);
SM4_Encrypt(sm4_contex->key,in,out);
dump_hex("enc data:",out,16);
}
else
{
dump_hex("cipher data:",in,16);
SM4_Decrypt(sm4_contex->key,in,out);
dump_hex("dec data:",out,16);
}
}
7编译和测试
make //编译出so文件,这个就是sm4的加密引擎库
make test 调用openssl命令进行测试该引擎
结果如下:
$ make test
openssl engine -t -c `pwd`/./bin/sm4-engine.so
(/home/yaomingyue/work/openssl/test/engine/sm4/v2/./bin/sm4-engine.so) A simple SM4 engine for demonstration purposes
Loaded: (SM4) A simple SM4 engine for demonstration purposes
[AES-128-ECB]
[ available ]
echo whatever | openssl enc -aes-128-ecb -e -out out.bin -K 0123456789ABCDEFFEDCBA9876543210 -iv 0123456789ABCDEFFEDCBA9876543210 -engine `pwd`/bin/sm4-engine.so
engine "SM4" set.
sm4_init get key:
1 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
get enc flag: 1
plain data::
77 68 61 74 65 76 65 72 a 7 7 7 7 7 7 7
enc data::
b6 63 68 23 aa ae f2 a6 e3 4 ac 33 ea 4b b2 2d
openssl enc -aes-128-ecb -d -in out.bin -K 0123456789ABCDEFFEDCBA9876543210 -engine `pwd`/bin/sm4-engine.so
engine "SM4" set.
sm4_init get key:
1 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
get enc flag: 0
cipher data::
b6 63 68 23 aa ae f2 a6 e3 4 ac 33 ea 4b b2 2d
dec data::
77 68 61 74 65 76 65 72 a 7 7 7 7 7 7 7
whatever