openssl 之EVP系列 PART I(1~6)

时间:2021-03-07 18:27:13


openssl之EVP系列之1---算法封装
    ---根据openssl doc\crypto\EVP.pod翻译和自己的理解写成
    (作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛,版本:openssl-0.9.7)
    
    EVP系列的函数定义包含在"evp.h"里面,这是一系列封装了openssl加密库里面所有算法的函数。通过这样的统一的封装,使得只需要在初始化参数的时候做很少的改变,就可以使用相同的代码但采用不同的加密算法进行数据的加密和解密。
    EVP系列函数主要封装了三大类型的算法,要支持全部这些算法,请调用OpenSSL_add_all_algorithms函数,下面分别就其结构作一个简单的介绍。
    【公开密钥算法】
    函数名称:EVP_Seal*...*,EVP_Open*...*
    功能描述:该系列函数封装提供了公开密钥算法的加密和解密功能,实现了电子信封的功能。
    相关文件:p_seal.c,p_open.c
    【数字签名算法】
    函数名称:EVP_Sign*...*,EVP_Verify*...*
    功能描述:该系列函数封装提供了数字签名算法和功能。
    相关文件:p_sign.c,p_verify.c
    【对称加密算法】
    函数名称:EVP_Encrypt*...*
    功能描述:该系列函数封装提供了对称加密算法的功能。
    相关文件:evp_enc.c,p_enc.c,p_dec.c,e_*.c
    【信息摘要算法】
    函数名称:EVP_Digest*...*
    功能描述:该系列函数封装实现了多种信息摘要算法。
    相关文件:digest.c,m_*.c
    【信息编码算法】
    函数名称:EVP_Encode*...*
    功能描述:该系列函数封装实现了ASCII码与二进制码之间的转换函数和功能。
    相关文件:encode.c



openssl之EVP系列之2---对称加密算法概述
    ---根据openssl doc\crypto\EVP_EncryptInit.pod和doc\ssleay.txt cipher.doc部分翻译和自己的理解写成
    (作者:DragonKing, Mail: wzhah@263.net ,发布于:http://gdwzh.126.com之openssl专业论坛,版本:openssl-0.9.7)
    
     对称加密算法封装的函数系列名字是以EVP_Encrypt*...*开头的,其实,这些函数只是简单调用了EVP_Cipher*...*系列的同名函数,换一个名字可能是为了更好的区别和理解。除了实现了对称加密算法外,EVP_Encrypt*...*系列还对块加密算法提供了缓冲功能。以后我们可能会更多使用EVP_Cipher的术语,因为它是真正的实现结构。
    EVP_Cipher*...*得以实现的一个基本结构是下面定义的一个算法结构,它定义了EVP_Cipher系列函数应该采用什么算法进行数据处理,其定义如下(evp.h):
    typedef 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 *);
     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); /* Miscellaneous operations */
     void *app_data;

    }EVP_CIPHER;


    下面对这个结构的部分成员的含义作一些解释:

  •     nid——是算法类型的nid识别号,openssl里面每个对象都有一个内部唯一的识别ID
  •     block_size——是每次加密的数据块的长度,以字节为单位
  •     key_len——各种不同算法缺省的密钥长度
  •     iv_len——初始化向量的长度
  •     init——算法结构初始化函数,可以设置为加密模式还是解密模式
  •     do_cipher——进行数据加密或解密的函数
  •     cleanup——释放EVP_CIPHER_CTX结构里面的数据和设置。
  •     ctx_size——设定ctx->cipher_data数据的长度
  •     set_asn1_parameters——在EVP_CIPHER_CTX结构中通过参数设置一个ASN1_TYPE
  •     get_asn1_parameters——从一个ASN1_TYPE中取得参数
  •     ctrl——其它各种操作函数
  •     app_data——应用数据

    通过定义这样一个指向这个结构的指针,你就可以在连接程序的时候只连接自己使用的算法;而如果你是通过一个整数来指明应该使用什么算法的话,会导致所有算法的代码都被连接到代码中。通过这样一个结构,还可以自己增加新的算法。
    在这个基础上,每个EVP_Cipher*...*函数都维护着一个指向一个EVP_CIPHER_CTX结构的指针。
    typedef 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];
     int num;
     void *app_data;
     int key_len;
     unsigned long flags;
     void *cipher_data;
     int final_used;
     int block_mask;
     unsigned char final[EVP_MAX_BLOCK_LENGTH];

     } EVP_CIPHER_CTX;


    下面对这个结构部分成员做简单的解释:

  •     cipher——是该结构相关的一个EVP_CIPHER算法结构
  •     engine——如果加密算法是ENGINE提供的,那么该成员保存了相关的函数接口
  •     encrypt——加密或解密的标志
  •     buf_len——该结构缓冲区里面当前的数据长度
  •     oiv——初始的初始化向量
  •     iv——工作时候使用的初始化向量
  •     buf——保存下来的部分需要数据
  •     num——在cfb/ofb模式的时候指定块长度
  •     app_data——应用程序要处理数据
  •     key_len——密钥长度,算法不一样长度也不一样
  •     cipher_data——加密后的数据

    
     上述两个结构是EVP_Cipher(EVP_Encrypt)系列的两个基本结构,它们的其它一些列函数都是以这两个结构为基础实现了。文件evp\ evp_enc.c是最高层的封装实现,各种加密的算法的封装在p_enc.c里面实现,解密算法的封装在p_dec.c里面实现,而各个e_*.c文件则是真正实现了各种算法的加解密功能,当然它们其实也是一些封装函数,真正的算法实现在各个算法同名目录里面的文件实现。


openssl之EVP系列之3---EVP_Encrypt支持的对称加密算法列表
    ---根据openssl doc\crypto\EVP_EncryptInit.pod和doc\ssleay.txt cipher.doc部分翻译和自己的理解写成
作者:DragonKing  Mail: 发布于:http://openssl.126.com 之openssl专业论坛

版本:openssl-0.9.7
    openssl对称加密算法的格式都以函数形式提供,其实该函数返回一个该算法的结构体,其形式一般如下:
    EVP_CIPHER* EVP_*(void)
    在openssl中,所有提供的对称加密算法长度都是固定的,有特别说明的除外。下面对这些算法进行分类的介绍,首先介绍一下算法中使用的通用标志的含义。
    【通用标志】

  •     ecb——电子密码本(Electronic Code Book)加密方式
  •     cbc——加密块链接(Cipher Block Chaining)加密方式
  •     cfb——64位加密反馈(Cipher Feedback)加密方式
  •     ofb——64位输出反馈(Output Feedback)加密方式
  •     ede——该加密算法采用了加密、解密、加密的方式,第一个密钥和最后一个密钥是相同的
  •     ede3——该加密算法采用了加密、解密、加密的方式,但是三个密钥都不相同    

    【NULL算法】
    函数:EVP_enc_null()
    说明:该算法不作任何事情,也就是没有进行加密处理

    【DES算法】
    函数:EVP_des_cbc(void), EVP_des_ecb(void), EVP_des_cfb(void), EVP_des_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的DES算法
    
    【使用两个密钥的3DES算法】
    函数:EVP_des_ede_cbc(void), EVP_des_ede(), EVP_des_ede_ofb(void),EVP_des_ede_cfb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的3DES算法,算法的第一个密钥和最后一个密钥相同,事实上就只需要两个密钥
    
    【使用三个密钥的3DES算法】
    函数:EVP_des_ede3_cbc(void), EVP_des_ede3(), EVP_des_ede3_ofb(void), EVP_des_ede3_cfb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的3DES算法,算法的三个密钥都不相同
    
    【DESX算法】
    函数:EVP_desx_cbc(void)
    说明:CBC方式DESX算法
    
    【RC4算法】
    函数:EVP_rc4(void)
    说明:RC4流加密算法。该算法的密钥长度可以改变,缺省是128位。
    
    【40位RC4算法】
    函数:EVP_rc4_40(void)
    说明:密钥长度40位的RC4流加密算法。该函数可以使用EVP_rc4和EVP_CIPHER_CTX_set_key_length函数代替。
    
    【IDEA算法】
    函数:EVP_idea_cbc(),EVP_idea_ecb(void), EVP_idea_cfb(void), EVP_idea_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的IDEA算法。
    
    【RC2算法】
    函数:EVP_rc2_cbc(void), EVP_rc2_ecb(void), EVP_rc2_cfb(void), EVP_rc2_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的RC2算法,该算法的密钥长度是可变的,可以通过设置有效密钥长度或有效密钥位来设置参数来改变。缺省的是128位。
    
    【定长的两种RC2算法】
    函数:EVP_rc2_40_cbc(void), EVP_rc2_64_cbc(void)
    说明:分别是40位和64位CBC模式的RC2算法。
    
    【Blowfish算法】
    函数:EVP_bf_cbc(void), EVP_bf_ecb(void), EVP_bf_cfb(void), EVP_bf_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的Blowfish算法,该算法的密钥长度是可变的
    
    【CAST算法】
    函数:EVP_cast5_cbc(void), EVP_cast5_ecb(void), EVP_cast5_cfb(void), EVP_cast5_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的CAST算法,该算法的密钥长度是可变的
    
    【RC5算法】
    函数:EVP_rc5_32_12_16_cbc(void), EVP_rc5_32_12_16_ecb(void), EVP_rc5_32_12_16_cfb(void), EVP_rc5_32_12_16_ofb(void)
     说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的RC5算法,该算法的密钥长度可以根据参数“number of rounds”(算法中一个数据块被加密的次数)来设置,缺省的是128位密钥,加密次数为12次。目前来说,由于RC5算法本身实现代码的限制,加密次数只能设置为8、12或16。
    
    【128位AES算法】
    函数:EVP_aes_128_ecb(void),EVP_aes_128_cbc(void),PEVP_aes_128_cfb(void),EVP_aes_128_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的128位AES算法
    
    【192位AES算法】
    函数:EVP_aes_192_ecb(void),EVP_aes_192_cbc(void),PEVP_aes_192_cfb(void),EVP_aes_192_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的192位AES算法
    
    【256位AES算法】
    函数:EVP_aes_256_ecb(void),EVP_aes_256_cbc(void),PEVP_aes_256_cfb(void),EVP_aes_256_ofb(void)
    说明:分别是CBC方式、ECB方式、CFB方式以及OFB方式的256位AES算法
    
    上述的算法是0.9.7版本支持的所有对称加密算法,关于算法的详细情况,请参看该算法的资料了或本系列后续的文章。

openssl之EVP系列之4---EVP_Encrypt系列函数详解(一)

    ---根据openssl doc\crypto\EVP_EncryptInit.pod和doc\ssleay.txt cipher.doc部分翻译和自己的理解写成
    (作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛,版本:openssl-0.9.7)

    EVP_Cipher 系列包含了很多函数,我将他们大概分成两部分来介绍,一部分是基本函数系列,就是本文要介绍的,另一个部分是设置函数系列,将在后面的文章进行介绍。基本系列函数主要是进行基本的加密和解密操作的函数,他们的定义如下(openssl\evp.h):
     int EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
    
     int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         ENGINE *impl, unsigned char *key, unsigned char *iv);
     int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
     int *outl, unsigned char *in, int inl);
     int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out,
     int *outl);
    
     int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         ENGINE *impl, unsigned char *key, unsigned char *iv);
     int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
     int *outl, unsigned char *in, int inl);
     int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
     int *outl);
    
     int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         ENGINE *impl, unsigned char *key, unsigned char *iv, int enc);
     int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
     int *outl, unsigned char *in, int inl);
     int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
     int *outl);
    
     int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         unsigned char *key, unsigned char *iv);
     int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out,
     int *outl);
    
     int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         unsigned char *key, unsigned char *iv);
     int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm,
     int *outl);
    
     int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
         unsigned char *key, unsigned char *iv, int enc);
     int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm,
     int *outl);
    
     int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
     其实在这里列出的函数虽然很多,但是大部分是功能重复的,有的是旧的版本支持的函数,新的版本中已经可以不再使用了。事实上,函数 EVP_EncryptInit, EVP_EncryptFinal, EVP_DecryptInit, EVP_CipherInit以及EVP_CipherFinal在新代码中不应该继续使用,他们保留下来只是为了兼容以前的代码。在新的代码中,应该使用EVP_EncryptInit_ex、EVP_EncryptFinal_ex、EVP_DecryptInit_ex、 EVP_DecryptFinal_ex、EVP_CipherInit_ex以及EVP_CipherFinal_ex函数,因为它们可以在每次调用完算法后,不用重新释放和分配已有EVP_CIPHER_CTX结构的内存的情况下重用该结构,方便很多。下面我们分别对这些函数进行介绍。

    【EVP_CIPHER_CTX_init】
    该函数初始化一个EVP_CIPHER_CTX结构体,只有初始化后该结构体才能在下面介绍的函数中使用。操作成功返回1,否则返回0。
    【EVP_EncryptInit_ex】
     该函数采用ENGINE参数impl的算法来设置并初始化加密结构体。其中,参数ctx必须在调用本函数之前已经进行了初始化。参数type通常通过函数类型来提供参数,如EVP_des_cbc函数的形式,即我们上一章中介绍的对称加密算法的类型。如果参数impl为NULL,那么就会使用缺省的实现算法。参数key是用来加密的对称密钥,iv参数是初始化向量(如果需要的话)。在算法中真正使用的密钥长度和初始化密钥长度是根据算法来决定的。在调用该函数进行初始化的时候,除了参数type之外,所有其它参数可以设置为NULL,留到以后调用其它函数的时候再提供,这时候参数type就设置为NULL 就可以了。在缺省的加密参数不合适的时候,可以这样处理。操作成功返回1,否则返回0。
    【EVP_EncryptUpdate】
     该函数执行对数据的加密。该函数加密从参数in输入的长度为inl的数据,并将加密好的数据写入到参数out里面去。可以通过反复调用该函数来处理一个连续的数据块。写入到out的数据数量是由已经加密的数据的对齐关系决定的,理论上来说,从0到(inl+cipher_block_size-1)的任何一个数字都有可能(单位是字节),所以输出的参数out要有足够的空间存储数据。写入到out中的实际数据长度保存在outl参数中。操作成功返回1,否则返回0。

    【EVP_EncryptFinal_ex】
    该函数处理最后(Final)的一段数据。在函数在 padding功能打开的时候(缺省)才有效,这时候,它将剩余的最后的所有数据进行加密处理。该算法使用标志的块padding方式(AKA PKCS padding)。加密后的数据写入到参数out里面,参数out的长度至少应该能够一个加密块。写入的数据长度信息输入到outl参数里面。该函数调用后,表示所有数据都加密完了,不应该再调用EVP_EncryptUpdate函数。如果没有设置padding功能,那么本函数不会加密任何数据,如果还有剩余的数据,那么就会返回错误信息,也就是说,这时候数据总长度不是块长度的整数倍。操作成功返回1,否则返回0。
    PKCS padding标准是这样定义的,在被加密的数据后面加上n个值为n的字节,使得加密后的数据长度为加密块长度的整数倍。无论在什么情况下,都是要加上 padding的,也就是说,如果被加密的数据已经是块长度的整数倍,那么这时候n就应该等于块长度。比如,如果块长度是9,要加密的数据长度是11,那么5个值为5的字节就应该增加在数据的后面。

    【EVP_DecryptInit_ex, EVP_DecryptUpdate和EVP_DecryptFinal_ex】
     这三个函数是上面三个函数相应的解密函数。这些函数的参数要求基本上都跟上面相应的加密函数相同。如果padding功能打开了, EVP_DecryptFinal会检测最后一段数据的格式,如果格式不正确,该函数会返回错误代码。此外,如果打开了padding功能, EVP_DecryptUpdate函数的参数out的长度应该至少为(inl+cipher_block_size)字节;但是,如果加密块的长度为 1,则其长度为inl字节就足够了。三个函数都是操作成功返回1,否则返回0。
    需要注意的是,虽然在padding功能开启的情况下,解密操作提供了错误检测功能,但是该功能并不能检测输入的数据或密钥是否正确,所以即便一个随机的数据块也可能无错的完成该函数的调用。如果padding 功能关闭了,那么当解密数据长度是块长度的整数倍时,操作总是返回成功的结果。

    【EVP_CipherInit_ex, EVP_CipherUpdate和EVP_CipherFinal_ex】
     事实上,上面介绍的函数都是调用这三个函数实现的,它们是更底层的函数。完成了数据的加密和解密功能。他们根据参数enc决定执行加密还是解密操作,如果 enc为1,则加密;如果enc为0,则解密;如果enc是-1,则不改变数据。三个函数都是操作成功返回1,否则返回0。

    【EVP_CIPHER_CTX_cleanup】
    该函数清除一个EVP_CIPHER_CTX结构中的所有信息并释放该结构占用的所有内存。在使用上述的函数完成一个加密算法过程后应该调用该函数,这样可以避免一些敏感信息遗留在内存造成安全隐犯。操作成功返回1,否则返回0。

    【EVP_EncryptInit, EVP_DecryptInit和EVP_CipherInit】
    这三个函数的功能分别跟函数EVP_EncryptInit_ex, EVP_DecryptInit_ex和EVP_CipherInit_ex功能相同,只是他们的ctx参数不需要进行初始化,并且使用缺省的算法库。三个函数都是操作成功返回1,否则返回0。

    【EVP_EncryptFinal, EVP_DecryptFinal和EVP_CipherFinal】
    这三个函数分别跟函数EVP_EncryptFinal_ex, EVP_DecryptFinal_ex以及EVP_CipherFinal_ex函数功能相同,不过,他们的参数ctx会在调用后自动释放。三个函数都是操作成功返回1,否则返回0。



openssl之EVP系列之5---EVP_Encrypt系列函数详解(二)

    ---根据openssl doc\crypto\EVP_EncryptInit.pod和doc\ssleay.txt cipher.doc部分翻译和自己的理解写成
    (作者:DragonKing, Mail: wzhah@263.net ,发布于:http://gdwzh.126.com之openssl专业论坛,版本:openssl-0.9.7)

    前面的文章我们介绍了EVP_ENcrypt系列函数的基本部分,本文将介绍他们的一些扩充部分,即一些参数设置和其它辅助的函数,其定义如下(openssl\evp.h):

     int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);
     int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
    
     const EVP_CIPHER *EVP_get_cipherbyname(const char *name);
     #define EVP_get_cipherbynid(a) EVP_get_cipherbyname(OBJ_nid2sn(a))
     #define EVP_get_cipherbyobj(a) EVP_get_cipherbynid(OBJ_obj2nid(a))
     int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
    
     #define EVP_CIPHER_nid(e) ((e)->nid)
     #define EVP_CIPHER_block_size(e) ((e)->block_size)
     #define EVP_CIPHER_key_length(e) ((e)->key_len)
     #define EVP_CIPHER_iv_length(e) ((e)->iv_len)
     #define EVP_CIPHER_flags(e) ((e)->flags)
     #define EVP_CIPHER_mode(e) ((e)->flags) & EVP_CIPH_MODE)
     int EVP_CIPHER_type(const EVP_CIPHER *ctx);
    
     #define EVP_CIPHER_CTX_cipher(e) ((e)->cipher)
     #define EVP_CIPHER_CTX_nid(e) ((e)->cipher->nid)
     #define EVP_CIPHER_CTX_block_size(e) ((e)->cipher->block_size)
     #define EVP_CIPHER_CTX_key_length(e) ((e)->key_len)
     #define EVP_CIPHER_CTX_iv_length(e) ((e)->cipher->iv_len)
     #define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data)
     #define EVP_CIPHER_CTX_set_app_data(e,d) ((e)->app_data=(char *)(d))
     #define EVP_CIPHER_CTX_type(c) EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c))
     #define EVP_CIPHER_CTX_flags(e) ((e)->cipher->flags)
     #define EVP_CIPHER_CTX_mode(e) ((e)->cipher->flags & EVP_CIPH_MODE)
    
     int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
     int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
    【EVP_CIPHER_CTX_set_padding】
     该函数设置是否采用padding功能.在算法缺省的情况下,是使用标准的块padding功能的,并且在解密的时候会自动接测padding并将它删除。如果将参数pad设置为0,则padding功能就会被禁止,那么在加密和解密的时候,数据应该为加密块长度的整数倍,否则就会出错。函数恒返回1。
    【EVP_CIPHER_CTX_set_key_length】
    该函数进行加密算法结构EVP_CIPHER_CTX密钥长度的设置。如果算法是一个密钥长度固定的算法,那么如果设置的密钥长度跟它固定的长度不一致,就会产生错误。
    【EVP_get_cipherbyname, EVP_get_cipherbynid和EVP_get_cipherbyobj】
    这三个函数都根据给定的参数返回一个EVP_CIPHER结构,不同的是给定的参数分别是算法名称、算法的NID和一个ASN1_OBJECT结构。具体的算法名称、NID以及ASN1_OBJECT结构请参看object\boject.h文件的定义。
    【EVP_CIPHER_nid和EVP_CIPHER_CTX_nid】
    这两个函数返回EVP_CIPHER或EVP_CIPHER_CTX结构内部的算法的NID。返回的NID值只是一个内部存储的值,并不一定真的有相应的OBJECT定义。
    【EVP_CIPHER_key_length和EVP_CIPHER_CTX_key_length】
     这两个函数返回EVP_CIPHER或EVP_CIPHER_CTX结构内部的算法的密钥长度。常量EVP_MAX_KEY_LENGTH定义了所有算法最长的密钥长度。需要注意的是,对于EVP_CIPHER_key_length函数来说,对特定的一种算法密钥长度是不变的,但是 EVP_CIPHER_CTX_key_length函数对同一个算法密钥长度却是可变的。
    【EVP_CIPHER_iv_length和EVP_CIPHER_CTX_iv_length】
    这两个函数返回EVP_CIPHER或EVP_CIPHER_CTX结构内部的算法的初始化向量长度。如果算法不使用IV,那么就会返回0。常量EVP_MAX_IV_LENGTH定义了所有算法最长的IV长度
    【EVP_CIPHER_block_size和EVP_CIPHER_CTX_block_size】
    这两个函数返回EVP_CIPHER或EVP_CIPHER_CTX结构内部的算法的加密块长度。常量EVP_MAX_IV_LENGTH也是所有算法最长的块长度。
    【EVP_CIPHER_type和EVP_CIPHER_CTX_type】
     这两个函数返回EVP_CIPHER或EVP_CIPHER_CTX结构内部的算法的类型。该类型的值是算法的NID,一般来说,NID忽略了算法的一些参数,如40位和129位RC2算法的NID是相同的。如果算法没有相应定义的NID或者不是ASN1所支持的,那么本函数就会返回NID_undef。
    【EVP_CIPHER_CTX_cipher】
    该函数返回EVP_CIPHER_CTX结构里面的EVP_CIPHER结构。
    【EVP_CIPHER_mode和EVP_CIPHER_CTX_mode】
     这两个函数返回相应结构算法的块加密模式,包括EVP_CIPH_ECB_MODE, EVP_CIPH_CBC_MODE, EVP_CIPH_CFB_MODE和EVP_CIPH_OFB_MODE;如果算法是流加密算法,那么就返回 EVP_CIPH_STREAM_CIPHER 。
    【EVP_CIPHER_param_to_asn1】
    该函数设置算法结构的参数,一般来说设置的值包括了所有参数和一个IV值。如果算法有IV,那么调用该函数时IV是必须设置的。该函数必须在所设置的算法结构使用之前(如调用EVP_EncryptUpdate和EVP_DecryptUpdate函数之前)调用。如果ASN1不支持该算法,那么调用该函数将导致失败。操作成功返回1,否则返回0。
    【EVP_CIPHER_asn1_to_param】
    该函数给用算法结构里面的值设置参数type的结构。其设置的内容由具体的算法决定。如在RC2算法中,它会设置IV和有效密钥长度。本函数应该在算法结构的基本算法类型已经设置了但是密钥还没有设置之前调用。例如,调用EVP_CipherInit函数的时候使用参数IV,并将key设置位NULL,然后就应该调用本函数,最后再调用EVP_CipherInit,这时候除了key设置位NULL外所有参数都应该设置。当ASN1不支持不支持该算法或者有参数不能设置的时候(如 RC2的有效密钥长度不支持),该函数调用就会失败。操作成功返回1,否则返回0。
    【EVP_CIPHER_CTX_ctrl】
    该函数可以设置不同算法的特定的参数。目前只有RC2算法的有效密钥长度和RC5算法的加密次数(rounds)可以进行设置。
    
    BTW:我自己感觉都写的有一点慢了,知道大家想知道怎么用来编程,但是,先把这么多函数介绍清楚了,下面看起来就会轻松多了,下一篇就将介绍EVP_Encrypt*...*系列函数的编程框架,并举几个例子。