EVP API是OpenSSL密码服务接口。EVP API屏蔽了具体算法的细节,为上层应用提供统一、抽象的接口。该接口的头文件为openssl/evp.h。
Libcrypto接口 OpenSSL提供了两个主要的函数库:libssl和libcrypto。libcrypto库提供了基本的关于密码学的一些常规函数,并且被libssl库所调用。但是也可以仅使用libcrypto库而不使用libssl库。
要使用libcrypto库,要将它放在开头位置
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
int main(int arc, char *argv[])
{
/* Load the human readable error strings for libcrypto */
ERR_load_crypto_strings();
/* Load all digest and cipher algorithms */
OpenSSL_add_all_algorithms();
/* Load config file, and other important initialisation */
OPENSSL_config(NULL);
/* ... Do some crypto stuff here ... */
/* Clean up */
/* Removes all digests and ciphers */
EVP_cleanup();
/* if you omit the next, a small leak may be left when you make use of the BIO (low level API) for e.g. base64 transformations */
CRYPTO_cleanup_all_ex_data();
/* Remove error strings */
ERR_free_strings();
return 0;
}
公钥密码系统参数生成
如果EVP_PKEY对象需要,EVP函数支持生成参数和密钥的功能。由于这些函数使用随机数,因此应当就像这里所讨论的确保随机数生成器采用适当的种子。
参数生成
仅支持以下EVP_PKEY类型的参数生成:
- EVP_PKEY_EC (用于SM2和椭圆曲线ECDSA、ECIES、ECDH密钥)
- EVP_PKEY_DSA
- EVP_PKEY_DH
以下的示例代码演示了如何为每种密钥类型产生参数的例子:
/* 创建用于生成参数的上下文 */
if(!(pctx = EVP_PKEY_CTX_new_id(type, NULL))) goto err;
if(!EVP_PKEY_paramgen_init(pctx)) goto err;
/* 根据类型设置paramgen参数 */
switch(type)
{
case EVP_PKEY_EC:
/* 使用在obj_mac.h中定义的NID_sm2p256v1命名曲线 */
if(!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2p256v1)) goto err;
break;
case EVP_PKEY_DSA:
/* 设置位长度为2048*/
if(!EVP_PKEY_CTX_set_dsa_paramgen_bits(pctx, 2048)) goto err;
break;
case EVP_PKEY_DH:
/* 设置一个2048位的素数 */
if(!EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, 2048)) goto err;
}
/* 生成参数 */
if (!EVP_PKEY_paramgen(pctx, ¶ms)) goto err;
密钥生成
以下示例代码演示了如何生成除EVP_PKEY HMAC和EVP_PKEY_CTX密钥之外的密钥的例子:
if(*params != NULL) {
if(!(kctx = EVP_PKEY_CTX_new(params, NULL))) goto err;
} else {
/* 创建用于生成密钥的上下文 */
if(!(kctx = EVP_PKEY_CTX_new_id(type, NULL))) goto err;
}
if(!EVP_PKEY_keygen_init(kctx)) goto err;
/* RSA密钥是在生成密钥期间设置密钥长度,而不是在生成参数的时候! */
if(type == EVP_PKEY_RSA) {
if(!EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 2048)) goto err;
}
/* 生成密钥 */
if (!EVP_PKEY_keygen(kctx, &key)) goto err;
这样就可以利用EVP抽象接口生成对应类型密钥。