分类: LINUX
2015-03-02 10:03:05
Openssl EVP(high-level cryptographic functions[1])提供了丰富的密码学中的各种函数。Openssl中实现了各种对称算法、摘要算法以及签名/验签算法。EVP函数将这些具体的算法进行了封装。
EVP主要封装了如下功能函数:
1)实现了base64编解码BIO;
2)实现了加解密BIO;
3)实现了摘要BIO;
4)实现了reliable BIO;
5)封装了摘要算法;
6)封装了对称加解密算法;
7)封装了非对称密钥的加密(公钥)、解密(私钥)、签名与验证以及辅助函数;
7)基于口令的加密(PBE);
8)对称密钥处理;
9)数字信封:数字信封用对方的公钥加密对称密钥,数据则用此对称密钥加密。发送给对方时,同时发送对称密钥密文和数据密文。接收方首先用自己的私钥解密密钥密文,得到对称密钥,然后用它解密数据。
10)其他辅助函数。
21.2 数据结构
EVP数据结构定义在crypto/evp.h中,如下所示:
21.2.1 EVP_PKEY
struct evp_pkey_st
{ int references; union { char *ptr; #ifndef OPENSSL_NO_RSA struct rsa_st *rsa; /* RSA */ #endif #ifndef OPENSSL_NO_DSA struct dsa_st *dsa; /* DSA */ #endif #ifndef OPENSSL_NO_DH struct dh_st *dh; /* DH */ #endif #ifndef OPENSSL_NO_EC struct ec_key_st *ec; /* ECC */ #endif } pkey; STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ };
该结构用来存放非对称密钥信息,可以是RSA、DSA、DH或ECC密钥。其中,ptr用来存放密钥结构地址,attributes堆栈用来存放密钥属性。
struct env_md_st { int type; int pkey_type; int md_size; unsigned long flags; int (*init)(EVP_MD_CTX *ctx); int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); int (*final)(EVP_MD_CTX *ctx,unsigned char *md); int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from); int (*cleanup)(EVP_MD_CTX *ctx); int (*sign)(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key); int (*verify)(int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key); int required_pkey_type[5]; int block_size; int ctx_size; /* how big does the ctx->md_data need to be */ } ;
该结构用来存放摘要算法信息、非对称算法类型以及各种计算函数。主要各项意义如下:
type:摘要类型,一般是摘要算法NID;
pkey_type:公钥类型,一般是签名算法NID;
md_size:摘要值大小,为字节数;
flags:用于设置标记;
init:摘要算法初始化函数;
update:多次摘要函数;
final:摘要完结函数;
copy:摘要上下文结构复制函数;
cleanup:清除摘要上下文函数;
sign:签名函数,其中key为非对称密钥结构地址;
verify:摘要函数,其中key为非对称密钥结构地址。
openssl对于各种摘要算法实现了上述结构,各个源码位于cypto/evp目录下,文件名以m_开头。Openssl通过这些结构来封装了各个摘要相关的运算。
struct evp_cipher_st { int nid; int block_size; int key_len; int iv_len; unsigned long flags; int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl); int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */ int ctx_size; int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); void *app_data; } ;
该结构用来存放对称加密相关的信息以及算法。主要各项意义如下:
nid:对称算法nid;
block_size:对称算法每次加解密的字节数;
key_len:对称算法的密钥长度字节数;
iv_len:对称算法的填充长度;
flags:用于标记;
init:加密初始化函数,用来初始化ctx,key为对称密钥值,iv为初始化向量,enc用于指明是要加密还是解密,这些信息存放在ctx中;
do_cipher:对称运算函数,用于加密或解密;
cleanup:清除上下文函数;
set_asn1_parameters:设置上下文参数函数;
get_asn1_parameters:获取上下文参数函数;
ctrl:控制函数;
app_data:用于存放应用数据。
openssl对于各种对称算法实现了上述结构,各个源码位于cypto/evp目录下,文件名以e_开头。Openssl通过这些结构来封装了对称算法相关的运算。
struct evp_cipher_ctx_st { const EVP_CIPHER *cipher; ENGINE *engine; int encrypt; int buf_len; unsigned char oiv[EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char buf[EVP_MAX_BLOCK_LENGTH]; /* 其他 */ unsigned char final[EVP_MAX_BLOCK_LENGTH]; } ;
对称算法上下文结构,此结构主要用来维护加解密状态,存放中间以及最后结果。因为加密或解密时,当数据很多时,可能会用到Update函数,并且每次加密或解密的输入数据长度任意的,并不一定是对称算法block_size的整数倍,所以需要用该结构来存放中间未加密的数据。主要项意义如下:
cipher:指明对称算法;
engine:硬件引擎;
encrypt:是加密还是解密;非0为加密,0为解密;
buf 和buf_len:指明还有多少数据未进行运算;
oiv:原始初始化向量;
iv:当前的初始化向量;
final:存放最终结果,一般与Final函数对应。
evp源码位于crypto/evp目录,可以分为如下几类:
1) 全局函数
主要包括c_allc.c、c_alld.c、c_all.c以及names.c。他们加载openssl支持的所有的对称算法和摘要算法,放入到哈希表中。实现了OpenSSL_add_all_digests、OpenSSL_add_all_ciphers以及OpenSSL_add_all_algorithms(调用了前两个函数)函数。在进行计算时,用户也可以单独加载摘要函数(EVP_add_digest)和对称计算函数(EVP_add_cipher)。
2) BIO扩充
包括bio_b64.c、bio_enc.c、bio_md.c和bio_ok.c,各自实现了BIO_METHOD方法,分别用于base64编解码、对称加解密以及摘要。
3) 摘要算法EVP封装
由digest.c实现,实现过程中调用了对应摘要算法的回调函数。各个摘要算法提供了自己的EVP_MD静态结构,对应源码为m_xxx.c。
4) 对称算法EVP封装
由evp_enc.c实现,实现过程调用了具体对称算法函数,实现了Update操作。各种对称算法都提供了一个EVP_CIPHER静态结构,对应源码为e_xxx.c。需要注意的是,e_xxx.c中不提供完整的加解密运算,它只提供基本的对于一个block_size数据的计算,完整的计算由evp_enc.c来实现。当用户想添加一个自己的对称算法时,可以参考e_xxx.c的实现方式。一般用户至少需要实现如下功能:
? 构造一个新的静态的EVP_CIPHER结构;
? 实现EVP_CIPHER结构中的init函数,该函数用于设置iv,设置加解密标记、以及根据外送密钥生成自己的内部密钥;
? 实现do_cipher函数,该函数仅对block_size字节的数据进行对称运算;
? 实现cleanup函数,该函数主要用于清除内存中的密钥信息。
5) 非对称算法EVP封装
主要是以p_开头的文件。其中,p_enc.c封装了公钥加密;p_dec.c封装了私钥解密;p_lib.c实现一些辅助函数;p_sign.c封装了签名函数;p_verify.c封装了验签函数;p_seal.c封装了数字信封;p_open.c封装了解数字信封。
6) 基于口令的加密
包括p5_crpt2.c、p5_crpt.c和evp_pbe.c。
典型的摘要函数主要有:
1) EVP_md5
返回md5的EVP_MD。
2) EVP_sha1
返回sha1的EVP_MD。
3) EVP_sha256
返回sha256的EVP_MD。
4) EVP_DigestInit
摘要初使化函数,需要有EVP_MD作为输入参数。
5) EVP_DigestUpdate和EVP_DigestInit_ex
摘要Update函数,用于进行多次摘要。
6) EVP_DigestFinal和EVP_DigestFinal_ex
摘要Final函数,用户得到最终结果。
7) EVP_Digest
对一个数据进行摘要,它依次调用了上述三个函数。
典型的加解密函数主要有:
1) EVP_CIPHER_CTX_init
初始化对称计算上下文。
2) EVP_CIPHER_CTX_cleanup
清除对称算法上下文数据,它调用用户提供的销毁函数销清除存中的内部密钥以及其他数据。
3) EVP_des_ede3_ecb
返回一个EVP_CIPHER;
4) EVP_EncryptInit和EVP_EncryptInit_ex
加密初始化函数,本函数调用具体算法的init回调函数,将外送密钥key转换为内部密钥形式,将初始化向量iv拷贝到ctx结构中。
5) EVP_EncryptUpdate
加密函数,用于多次计算,它调用了具体算法的do_cipher回调函数。
6) EVP_EncryptFinal和EVP_EncryptFinal_ex
获取加密结果,函数可能涉及填充,它调用了具体算法的do_cipher回调函数。
7) EVP_DecryptInit和EVP_DecryptInit_ex
解密初始化函数。
8) EVP_DecryptUpdate
解密函数,用于多次计算,它调用了具体算法的do_cipher回调函数。
9) EVP_DecryptFinal和EVP_DecryptFinal_ex
获取解密结果,函数可能涉及去填充,它调用了具体算法的do_cipher回调函数。
10)EVP_BytesToKey
计算密钥函数,它根据算法类型、摘要算法、salt以及输入数据计算出一个对称密钥和初始化向量iv。
11)PKCS5_PBE_keyivgen和PKCS5_v2_PBE_keyivgen
实现了PKCS5基于口令生成密钥和初始化向量的算法。
12)PKCS5_PBE_add
加载所有openssl实现的基于口令生成密钥的算法。
13)EVP_PBE_alg_add
添加一个PBE算法。
典型的非对称函数有:
1) EVP_PKEY_encrypt
公钥加密。
2) EVP_PKEY_decrypt
私钥解密。
3) EVP_PKEY_assign
设置EVP_PKEY中具体的密钥结构,使它代表该密钥。
4) EVP_PKEY_assign_RSA/ EVP_PKEY_set1_RSA
设置EVP_PKEY中的RSA密钥结构,使它代表该RSA密钥。
5) EVP_PKEY_get1_RSA
获取EVP_PKEY的RSA密钥结构。
6) EVP_SignFinal
签名操作,输入参数必须有私钥(EVP_PKEY)。
7) EVP_VerifyFinal
验证签名,输入参数必须有公钥(EVP_PKEY)。
8) int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,const unsigned char *ek, int ekl, const unsigned char *iv,EVP_PKEY *priv)
解数字信封初始化操作,type为对称加密算法,ek为密钥密文,ekl为密钥密文长度,iv为填充值,priv为用户私钥。
9) EVP_OpenUpdate
做解密运算。
10) EVP_OpenFinal
做解密运算,解开数字信封。
11) int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, unsigned char **ek,int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk)
type为对称算法,ek数组用来存放多个公钥对密钥加密的结果,ekl用于存放ek数组中每个密钥密文的长度,iv为填充值,pubk数组用来存放多个公钥,npubk为公钥个数,本函数用多个公钥分别加密密钥,并做加密初始化。
12)EVP_SealUpdate
做加密运算。
EVP_SealFinal
做加密运算,制作数字信封。
1) EVP_EncodeInit
BASE64编码初始化。
2) EVP_EncodeUpdate
BASE64编码,可多次调用。
3) EVP_EncodeFinal
BASE64编码,并获取最终结果。
4) EVP_DecodeInit
BASE64解码初始化。
5) EVP_DecodeUpdate
输入数据长度不能大于80字节。BASE64解码可多次调用,注意,本函数的输入数据不能太长。
6) EVP_DecodeFinal
BASE64解码,并获取最终结果。
7)EVP_EncodeBlock
BASE64编码函数,本函数可单独调用。
8)EVP_DecodeBlock
BASE64解码,本函数可单独调用,对输入数据长度无要求。
1) EVP_add_cipher
将对称算法加入到全局变量,以供调用。
2) EVP_add_digest
将摘要算法加入到全局变量中,以供调用。
3) EVP_CIPHER_CTX_ctrl
对称算法控制函数,它调用了用户实现的ctrl回调函数。
4) EVP_CIPHER_CTX_set_key_length
当对称算法密钥长度为可变长时,设置对称算法的密钥长度。
5) EVP_CIPHER_CTX_set_padding
设置对称算法的填充,对称算法有时候会涉及填充。加密分组长度大于一时,用户输入数据不是加密分组的整数倍时,会涉及到填充。填充在最后一个分组来完成,openssl分组填充时,如果有n个填充,则将最后一个分组用n来填满。
6) EVP_CIPHER_get_asn1_iv
获取原始iv,存放在ASN1_TYPE结构中。
7) EVP_CIPHER_param_to_asn1
设置对称算法参数,参数存放在ASN1_TYPE类型中,它调用用户实现的回调函数set_asn1_parameters来实现。
8) EVP_CIPHER_type
获取对称算法的类型。
9) EVP_CipherInit/EVP_CipherInit_ex
对称算法计算(加/解密)初始化函数,_ex函数多了硬件enginge参数,EVP_EncryptInit和EVP_DecryptInit函数也调用本函数。
10) EVP_CipherUpdate
对称计算(加/解密)函数,它调用了EVP_EncryptUpdate和EVP_DecryptUpdate函数。
11) EVP_CipherFinal/EVP_CipherFinal_ex
对称计算(加/解)函数,调用了EVP_EncryptFinal(_ex)和EVP_DecryptFinal(_ex);本函数主要用来处理最后加密分组,可能会有对称计算。
12)EVP_cleanup
清除加载的各种算法,包括对称算法、摘要算法以及PBE算法,并清除这些算法相关的哈希表的内容。
13) EVP_get_cipherbyname
根据字串名字来获取一种对称算法(EVP_CIPHER),本函数查询对称算法哈希表。
14) EVP_get_digestbyname
根据字串获取摘要算法(EVP_MD),本函数查询摘要算法哈希表。
15) EVP_get_pw_prompt
获取口令提示信息字符串.
16)int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
PBE初始化函数。本函数用口令生成对称算法的密钥和初始化向量,并作加/解密初始化操作。本函数再加上后续的EVP_CipherUpdate以及EVP_CipherFinal_ex构成一个完整的加密过程(可参考crypto/p12_decr.c的PKCS12_pbe_crypt函数).
17) EVP_PBE_cleanup
删除所有的PBE信息,释放全局堆栈中的信息.
18)EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8)
将PKCS8_PRIV_KEY_INFO(x509.h中定义)中保存的私钥转换为EVP_PKEY结构。
19) EVP_PKEY2PKCS8/EVP_PKEY2PKCS8_broken
将EVP_PKEY结构中的私钥转换为PKCS8_PRIV_KEY_INFO数据结构存储。
20) EVP_PKEY_bits
非对称密钥大小,为比特数。
21) EVP_PKEY_cmp_parameters
比较非对称密钥的密钥参数,用于DSA和ECC密钥。
22)EVP_PKEY_copy_parameters
拷贝非对称密钥的密钥参数,用于DSA和ECC密钥。
23)EVP_PKEY_free
释放非对称密钥数据结构。
24) EVP_PKEY_get1_DH/EVP_PKEY_set1_DH
获取/设置EVP_PKEY中的DH密钥。
25) EVP_PKEY_get1_DSA/EVP_PKEY_set1_DSA
获取/设置EVP_PKEY中的DSA密钥。
26)EVP_PKEY_get1_RSA/EVP_PKEY_set1_RSA
获取/设置EVP_PKEY中结构中的RSA结构密钥。
27) EVP_PKEY_missing_parameters
检查非对称密钥参数是否齐全,用于DSA和ECC密钥。
28) EVP_PKEY_new
生成一个EVP_PKEY结构。
29) EVP_PKEY_size
获取非对称密钥的字节大小。
30) EVP_PKEY_type
获取EVP_PKEY中表示的非对称密钥的类型。
31)int EVP_read_pw_string(char *buf,int length,const char *prompt,int verify)
获取用户输入的口令;buf用来存放用户输入的口令,length为buf长度,prompt为提示给用户的信息,如果为空,它采用内置的提示信息,verify为0时,不要求验证用户输入的口令,否则回要求用户输入两遍。返回0表示成功。
32) EVP_set_pw_prompt
设置内置的提示信息,用于需要用户输入口令的场合。
对称加密过程如下:
1) EVP_EncryptInit:
设置buf_len为0,表明临时缓冲区buf没有数据。
2) EVP_EncryptUpdate:
ctx结构中的buf缓冲区用于存放上次EVP_EncryptUpdate遗留下来的未加密的数据,buf_len指明其长度。如果buf_len为0,加密的时候先加密输入数据的整数倍,将余下的数据拷贝到buf缓冲区。如果buf_len不为0,先加密buf里面的数据和输入数据的一部分(凑足一个分组的长度),然后用上面的方法加密,输出结果是加过密的数据。
3) EVP_ EncryptFinal
加密ctx的buf中余下的数据,如果长度不够一个分组(分组长度不为1),则填充,然后再加密,输出结果。
总之,加密大块数据(比如一个大的文件,多出调用EVP_EncryptUpdate)的结果等效于将所有的数据一次性读入内存进行加密的结果。加密和解密时每次计算的数据块的大小不影响其运算结果。
1)示例1
#include#include int main() { int ret,which=1; EVP_CIPHER_CTX ctx; const EVP_CIPHER *cipher; unsigned char key[24],iv[8],in[100],out[108],de[100]; int i,len,inl,outl,total=0; for(i=0;i<24;i++) { memset(&key[i],i,1); } for(i=0;i<8;i++) { memset(&iv[i],i,1); } for(i=0;i<100;i++) { memset(&in[i],i,1); } EVP_CIPHER_CTX_init(&ctx); printf("please select :\n"); printf("1: EVP_des_ede3_ofb\n"); printf("2: EVP_des_ede3_cbc\n"); scanf("%d",&which); if(which==1) cipher=EVP_des_ede3_ofb(); else cipher=EVP_des_ede3_cbc(); ret=EVP_EncryptInit_ex(&ctx,cipher,NULL,key,iv); if(ret!=1) { printf("EVP_EncryptInit_ex err1!\n"); return -1; } inl=50; len=0; EVP_EncryptUpdate(&ctx,out+len,&outl,in,inl); len+=outl; EVP_EncryptUpdate(&ctx,out+len,&outl,in+50,inl); len+=outl; EVP_EncryptFinal_ex(&ctx,out+len,&outl); len+=outl; printf("加密结果长度:%d\n",len); /* 解密 */ EVP_CIPHER_CTX_cleanup(&ctx); EVP_CIPHER_CTX_init(&ctx); ret=EVP_DecryptInit_ex(&ctx,cipher,NULL,key,iv); if(ret!=1) { printf("EVP_DecryptInit_ex err1!\n"); return -1; } total=0; EVP_DecryptUpdate(&ctx,de+total,&outl,out,44); total+=outl; EVP_DecryptUpdate(&ctx,de+total,&outl,out+44,len-44); total+=outl; ret=EVP_DecryptFinal_ex(&ctx,de+total,&outl); total+=outl; if(ret!=1) { EVP_CIPHER_CTX_cleanup(&ctx); printf("EVP_DecryptFinal_ex err\n"); return -1; } if((total!=100) || (memcmp(de,in,100))) { printf("err!\n"); return -1; } EVP_CIPHER_CTX_cleanup(&ctx); printf("test ok!\n"); return 0; }
输出结果如下:
please select :
1: EVP_des_ede3_ofb
2: EVP_des_ede3_cbc
1
加密结果长度:100
test ok!
please select :
1: EVP_des_ede3_ofb
2: EVP_des_ede3_cbc
2
加密结果长度:104
test ok!
2)示例2
#include#include int main() { int cnid,ret,i,msize,mtype; int mpktype,cbsize,mnid,mbsize; const EVP_CIPHER *type; const EVP_MD *md; int datal,count,keyl,ivl; unsigned char salt[20],data[100],*key,*iv; const char *cname,*mname; type=EVP_des_ecb(); cnid=EVP_CIPHER_nid(type); cname=EVP_CIPHER_name(type); cbsize=EVP_CIPHER_block_size(type); printf("encrypto nid : %d\n",cnid); printf("encrypto name: %s\n",cname); printf("encrypto bock size : %d\n",cbsize); md=EVP_md5(); mtype=EVP_MD_type(md); mnid=EVP_MD_nid(md); mname=EVP_MD_name(md); mpktype=EVP_MD_pkey_type(md); msize=EVP_MD_size(md); mbsize=EVP_MD_block_size(md); printf("md info : \n"); printf("md type : %d\n",mtype); printf("md nid : %d\n",mnid); printf("md name : %s\n",mname); printf("md pkey type : %d\n",mpktype); printf("md size : %d\n",msize); printf("md block size : %d\n",mbsize); keyl=EVP_CIPHER_key_length(type); key=(unsigned char *)malloc(keyl); ivl=EVP_CIPHER_iv_length(type); iv=(unsigned char *)malloc(ivl); for(i=0;i<100;i++) memset(&data[i],i,1); for(i=0;i<20;i++) memset(&salt[i],i,1); datal=100; count=2; ret=EVP_BytesToKey(type,md,salt,data,datal,count,key,iv); printf("generate key value: \n"); for(i=0;i printf("%x ",*(key+i)); printf("\n"); printf("generate iv value: \n"); for(i=0;i printf("%x ",*(iv+i)); printf("\n"); return 0; }
EVP_BytesToKey函数通过salt以及data数据来生成所需要的key和iv。
输出:
encrypto nid : 29
encrypto name: DES-ECB
encrypto bock size : 8
md info :
md type : 4
md nid : 4
md name : MD5
md pkey type : 8
md size : 16
md block size : 64
generate key value:
54 0 b1 24 18 42 8d dd
generate iv value:
ba 7d c3 97 a0 c9 e0 70
3) 示例3
#include#include int main() { int ret,inlen,outlen=0; unsigned long e=RSA_3; char data[100],out[500]; EVP_MD_CTX md_ctx,md_ctx2; EVP_PKEY *pkey; RSA *rkey; BIGNUM *bne; /* 待签名数据*/ strcpy(data,"openssl 编程作者:赵春平"); inlen=strlen(data); /* 生成RSA密钥*/ bne=BN_new(); ret=BN_set_word(bne,e); rkey=RSA_new(); ret=RSA_generate_key_ex(rkey,1024,bne,NULL); if(ret!=1) goto err; pkey=EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey,rkey); /* 初始化*/ EVP_MD_CTX_init(&md_ctx); ret=EVP_SignInit_ex(&md_ctx,EVP_md5(), NULL); if(ret!=1) goto err; ret=EVP_SignUpdate(&md_ctx,data,inlen); if(ret!=1) goto err; ret=EVP_SignFinal(&md_ctx,out,&outlen,pkey); /* 验证签名*/ EVP_MD_CTX_init(&md_ctx2); ret=EVP_VerifyInit_ex(&md_ctx2,EVP_md5(), NULL); if(ret!=1) goto err; ret=EVP_VerifyUpdate(&md_ctx2,data,inlen); if(ret!=1) goto err; ret=EVP_VerifyFinal(&md_ctx2,out,outlen,pkey); if(ret==1) printf("验证成功\n"); else printf("验证错误\n"); err: RSA_free(rkey); BN_free(bne); return 0; }
4)示例4
#include#include int main() { int ret,ekl[2],npubk,inl,outl,total=0,total2=0; unsigned long e=RSA_3; char *ek[2],iv[8],in[100],out[500],de[500]; EVP_CIPHER_CTX ctx,ctx2; EVP_CIPHER *type; EVP_PKEY *pubkey[2]; RSA *rkey; BIGNUM *bne; /* 生成RSA密钥*/ bne=BN_new(); ret=BN_set_word(bne,e); rkey=RSA_new(); ret=RSA_generate_key_ex(rkey,1024,bne,NULL); pubkey[0]=EVP_PKEY_new(); EVP_PKEY_assign_RSA(pubkey[0],rkey); type=EVP_des_cbc(); npubk=1; EVP_CIPHER_CTX_init(&ctx); ek[0]=malloc(500); ek[1]=malloc(500); ret=EVP_SealInit(&ctx,type,ek,ekl,iv,pubkey,1); /* 只有一个公钥*/ if(ret!=1) goto err; strcpy(in,"openssl 编程"); inl=strlen(in); ret=EVP_SealUpdate(&ctx,out,&outl,in,inl); if(ret!=1) goto err; total+=outl; ret=EVP_SealFinal(&ctx,out+outl,&outl); if(ret!=1) goto err; total+=outl; memset(de,0,500); EVP_CIPHER_CTX_init(&ctx2); ret=EVP_OpenInit(&ctx2,EVP_des_cbc(),ek[0],ekl[0],iv,pubkey[0]); if(ret!=1) goto err; ret=EVP_OpenUpdate(&ctx2,de,&outl,out,total); total2+=outl; ret=EVP_OpenFinal(&ctx2,de+outl,&outl); total2+=outl; de[total2]=0; printf("%s\n",de); err: free(ek[0]); free(ek[1]); EVP_PKEY_free(pubkey[0]); BN_free(bne); getchar(); return 0; }
输出结果:openssl 编程