openssl系列函数api.docx
- 文档编号:12581758
- 上传时间:2023-04-20
- 格式:DOCX
- 页数:44
- 大小:39.23KB
openssl系列函数api.docx
《openssl系列函数api.docx》由会员分享,可在线阅读,更多相关《openssl系列函数api.docx(44页珍藏版)》请在冰豆网上搜索。
openssl系列函数api
Openssl之EVP系列
作者:
LaoKa
20080426
1.算法封装
EVP系列的函数定义包含在"evp.h"里面,这是一系列封装了openssl加密库里面所有算法的函数。
通过这样的统一的封装,使得只需要在初始化参数的时候做很少的改变,就可以使用相同的代码但采用不同的加密算法进行数据的加密和解密。
EVP系列函数主要封装了三大类型的算法,要支持全部这些算法,请调用OpenSSL_add_all_algorithms函数,下面分别就其结构作一个简单的介绍。
1.1公开密钥算法
函数名称:
EVP_Seal*...*,EVP_Open*...*
功能描述:
该系列函数封装提供了公开密钥算法的加密和解密功能,实现了电子信封的功能。
相关文件:
p_seal.c,p_open.c
1.2数字签名算法
函数名称:
EVP_Sign*...*,EVP_Verify*...*
功能描述:
该系列函数封装提供了数字签名算法和功能。
相关文件:
p_sign.c,p_verify.c
1.3对称加密算法
函数名称:
EVP_Encrypt*...*
功能描述:
该系列函数封装提供了对称加密算法的功能。
相关文件:
evp_enc.c,p_enc.c,p_dec.c,e_*.c
1.4信息摘要算法
函数名称:
EVP_Digest*...*
功能描述:
该系列函数封装实现了多种信息摘要算法。
相关文件:
digest.c,m_*.c
1.5信息编码算法
函数名称:
EVP_Encode*...*
功能描述:
该系列函数封装实现了ASCII码与二进制码之间的转换函数和功能。
相关文件:
encode.c
注意:
自从出现engin版本以后,所有对称加密算法和摘要算法可以用ENGINE模块实现的算法代替。
如果ENGINE模块实现的对称加密和信息摘要函数被注册为缺省的实现算法,那么当使用各种EVP函数时,软件编译的时候会自动将该实现模块连接进去。
2.对称加密算法概述
对称加密算法封装的函数系列名字是以EVP_Encrypt*...*开头的,其实,这些函数只是简单调用了EVP_Cipher*...*系列的同名函数,换一个名字可能是为了更好的区别和理解。
除了实现了对称加密算法外,EVP_Encrypt*...*系列还对块加密算法提供了缓冲功能。
以后我们可能会更多使用EVP_Cipher的术语,因为它是真正的实现结构。
EVP_Cipher*...*得以实现的一个基本结构是下面定义的一个算法结构,它定义了EVP_Cipher系列函数应该采用什么算法进行数据处理,其定义如下(evp.h):
typedefstructevp_cipher_st
{
intnid;
intblock_size;
intkey_len;
intiv_len;
unsignedlongflags;
int(*init)(EVP_CIPHER_CTX*ctx,constunsignedchar*key,constunsignedchar*iv,intenc);
int(*do_cipher)(EVP_CIPHER_CTX*ctx,unsignedchar*out,constunsignedchar*in,unsignedintinl);
int(*cleanup)(EVP_CIPHER_CTX*);
intctx_size;
int(*set_asn1_parameters)(EVP_CIPHER_CTX*,ASN1_TYPE*);
int(*get_asn1_parameters)(EVP_CIPHER_CTX*,ASN1_TYPE*);
int(*ctrl)(EVP_CIPHER_CTX*,inttype,intarg,void*ptr);/*Miscellaneousoperations*/
void*app_data;
}EVP_CIPHER;
下面对这个结构的部分成员的含义作一些解释:
1.nid——是算法类型的nid识别号,openssl里面每个对象都有一个内部唯一的识别ID
2.block_size——是每次加密的数据块的长度,以字节为单位
3.key_len——各种不同算法缺省的密钥长度
4.iv_len——初始化向量的长度
5.init——算法结构初始化函数,可以设置为加密模式还是解密模式
6.do_cipher——进行数据加密或解密的函数
7.cleanup——释放EVP_CIPHER_CTX结构里面的数据和设置。
8.ctx_size——设定ctx->cipher_data数据的长度
9.set_asn1_parameters——在EVP_CIPHER_CTX结构中通过参数设置一个ASN1_TYPE
10.get_asn1_parameters——从一个ASN1_TYPE中取得参数
11.ctrl——其它各种操作函数
12.app_data——应用数据
通过定义这样一个指向这个结构的指针,你就可以在连接程序的时候只连接自己使用的算法;而如果你是通过一个整数来指明应该使用什么算法的话,会导致所有算法的代码都被连接到代码中。
通过这样一个结构,还可以自己增加新的算法。
在这个基础上,每个EVP_Cipher*...*函数都维护着一个指向一个EVP_CIPHER_CTX结构的指针。
typedefstructevp_cipher_ctx_st
{
constEVP_CIPHER*cipher;
ENGINE*engine;
intencrypt;
intbuf_len;
unsignedcharoiv[EVP_MAX_IV_LENGTH];
unsignedchariv[EVP_MAX_IV_LENGTH];
unsignedcharbuf[EVP_MAX_BLOCK_LENGTH];
intnum;
void*app_data;
intkey_len;
unsignedlongflags;
void*cipher_data;
intfinal_used;
intblock_mask;
unsignedcharfinal[EVP_MAX_BLOCK_LENGTH];
}EVP_CIPHER_CTX;
下面对这个结构部分成员做简单的解释:
1.cipher——是该结构相关的一个EVP_CIPHER算法结构
2.engine——如果加密算法是ENGINE提供的,那么该成员保存了相关的函数接口
3.encrypt——加密或解密的标志
4.buf_len——该结构缓冲区里面当前的数据长度
5.oiv——初始的初始化向量
6.iv——工作时候使用的初始化向量
7.buf——保存下来的部分需要数据
8.num——在cfb/ofb模式的时候指定块长度
9.app_data——应用程序要处理数据
10.key_len——密钥长度,算法不一样长度也不一样
11.cipher_data——加密后的数据
上述两个结构是EVP_Cipher(EVP_Encrypt)系列的两个基本结构,它们的其它一些列函数都是以这两个结构为基础实现了。
文件evp\evp_enc.c是最高层的封装实现,各种加密的算法的封装在p_enc.c里面实现,解密算法的封装在p_dec.c里面实现,而各个e_*.c文件则是真正实现了各种算法的加解密功能,当然它们其实也是一些封装函数,真正的算法实现在各个算法同名目录里面的文件实现。
3.EVP_Encrypt支持的对称加密算法列表
openssl对称加密算法的格式都以函数形式提供,其实该函数返回一个该算法的结构体,其形式一般如下:
EVP_CIPHER*EVP_*(void)
在openssl中,所有提供的对称加密算法长度都是固定的,有特别说明的除外。
下面对这些算法进行分类的介绍,首先介绍一下算法中使用的通用标志的含义。
通用标志:
ecb——电子密码本(ElectronicCodeBook)加密方式
cbc——加密块链接(CipherBlockChaining)加密方式
cfb——64位加密反馈(CipherFeedback)加密方式
ofb——64位输出反馈(OutputFeedback)加密方式
ede——该加密算法采用了加密、解密、加密的方式,第一个密钥和最后一个密钥是相同的
ede3——该加密算法采用了加密、解密、加密的方式,但是三个密钥都不相同
3.1NULL算法
函数:
EVP_enc_null()
说明:
该算法不作任何事情,也就是没有进行加密处理
3.2DES算法
函数:
EVP_des_cbc(void),EVP_des_ecb(void),EVP_des_cfb(void),EVP_des_ofb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的DES算法
3.3使用两个密钥的3DES算法
函数:
EVP_des_ede_cbc(void),EVP_des_ede(),EVP_des_ede_ofb(void),EVP_des_ede_cfb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的3DES算法,算法的第一个密钥和最后一个密钥相同,事实上就只需要两个密钥
3.4使用三个密钥的3DES算法
函数:
EVP_des_ede3_cbc(void),EVP_des_ede3(),EVP_des_ede3_ofb(void),EVP_des_ede3_cfb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的3DES算法,算法的三个密钥都不相同
3.5DESX算法
函数:
EVP_desx_cbc(void)
说明:
CBC方式DESX算法
3.6RC4算法
函数:
EVP_rc4(void)
说明:
RC4流加密算法。
该算法的密钥长度可以改变,缺省是128位。
3.740位RC4算法
函数:
EVP_rc4_40(void)
说明:
密钥长度40位的RC4流加密算法。
该函数可以使用EVP_rc4和EVP_CIPHER_CTX_set_key_length函数代替。
3.8IDEA算法
函数:
EVP_idea_cbc(),EVP_idea_ecb(void),EVP_idea_cfb(void),EVP_idea_ofb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的IDEA算法。
3.9RC2算法
函数:
EVP_rc2_cbc(void),EVP_rc2_ecb(void),EVP_rc2_cfb(void),EVP_rc2_ofb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的RC2算法,该算法的密钥长度是可变的,可以通过设置有效密钥长度或有效密钥位来设置参数来改变。
缺省的是128位。
3.10定长的两种RC2算法
函数:
EVP_rc2_40_cbc(void),EVP_rc2_64_cbc(void)
说明:
分别是40位和64位CBC模式的RC2算法。
3.11Blowfish算法
函数:
EVP_bf_cbc(void),EVP_bf_ecb(void),EVP_bf_cfb(void),EVP_bf_ofb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的Blowfish算法,该算法的密钥长度是可变的
3.12CAST算法
函数:
EVP_cast5_cbc(void),EVP_cast5_ecb(void),EVP_cast5_cfb(void),EVP_cast5_ofb(void)
说明:
分别是CBC方式、ECB方式、CFB方式以及OFB方式的CAST算法,该算法的密钥长度是可变的
3.13RC5算法
函数:
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算法,该算法的密钥长度可以根据参数“numberofrounds”(算法中一个数据块被加密的次数)来设置,缺省的是128位密钥,加密次数为12次。
目前来说,由于RC5算法本身实现代码的限制,加密次数只能设置为8、12或16。
3.14128位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算法
3.15192位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算法
3.16256位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算法
4.EVP_Encrypt系列函数详解
(一)
EVP_Cipher系列包含了很多函数,我将他们大概分成两部分来介绍,一部分是基本函数系列,就是本文要介绍的,另一个部分是设置函数系列,将在后面的文章进行介绍。
基本系列函数主要是进行基本的加密和解密操作的函数,他们的定义如下(openssl\evp.h):
intEVP_CIPHER_CTX_init(EVP_CIPHER_CTX*a);
intEVP_EncryptInit_ex(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,ENGINE*impl,unsignedchar*key,unsignedchar*iv);
intEVP_EncryptUpdate(EVP_CIPHER_CTX*ctx,unsignedchar*out,int*outl,unsignedchar*in,intinl);
intEVP_EncryptFinal_ex(EVP_CIPHER_CTX*ctx,unsignedchar*out,int*outl);
intEVP_DecryptInit_ex(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,ENGINE*impl,unsignedchar*key,unsignedchar*iv);
intEVP_DecryptUpdate(EVP_CIPHER_CTX*ctx,unsignedchar*out,int*outl,unsignedchar*in,intinl);
intEVP_DecryptFinal_ex(EVP_CIPHER_CTX*ctx,unsignedchar*outm,int*outl);
intEVP_CipherInit_ex(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,ENGINE*impl,unsignedchar*key,unsignedchar*iv,intenc);
intEVP_CipherUpdate(EVP_CIPHER_CTX*ctx,unsignedchar*out,int*outl,unsignedchar*in,intinl);
intEVP_CipherFinal_ex(EVP_CIPHER_CTX*ctx,unsignedchar*outm,int*outl);
intEVP_EncryptInit(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,unsignedchar*key,unsignedchar*iv);
intEVP_EncryptFinal(EVP_CIPHER_CTX*ctx,unsignedchar*out,int*outl);
intEVP_DecryptInit(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,unsignedchar*key,unsignedchar*iv);
intEVP_DecryptFinal(EVP_CIPHER_CTX*ctx,unsignedchar*outm,int*outl);
intEVP_CipherInit(EVP_CIPHER_CTX*ctx,constEVP_CIPHER*type,unsignedchar*key,unsignedchar*iv,intenc);
intEVP_CipherFinal(EVP_CIPHER_CTX*ctx,unsignedchar*outm,int*outl);
intEVP_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结构的内存的情况下重用该结构,方便很多。
下面我们分别对这些函数进行介绍。
4.1EVP_CIPHER_CTX_init
该函数初始化一个EVP_CIPHER_CTX结构体,只有初始化后该结构体才能在下面介绍的函数中使用。
操作成功返回1,否则返回0。
4.2EVP_EncryptInit_ex
该函数采用ENGINE参数impl的算法来设置并初始化加密结构体。
其中,参数ctx必须在调用本函数之前已经进行了初始化。
参数type通常通过函数类型来提供参数,如EVP_des_cbc函数的形式,即我们上一章中介绍的对称加密算法的类型。
如果参数impl为NULL,那么就会使用缺省的实现算法。
参数key是用来加密的对称密钥,iv参数是初始化向量(如果需要的话)。
在算法中真正使用的密钥长度和初始化密钥长度是根据算法来决定的。
在调用该函数进行初始化的时候,除了参数type之外,所有其它参数可以设置为NULL,留到以后调用其它函数的时候再提供,这时候参数type就设置为NULL就可以了。
在缺省的加密参数不合适的时候,可以这样处理。
操作成功返回1,否则返回0。
4.3EVP_EncryptUpdate
该函数执行对数据的加密。
该函数加密从参数in输入的长度为inl的数据,并将加密好的数据写入到参数out里面去。
可以通过反复调用该函数来处理一个连续的数据块。
写入到out的数据数量是由已经加密的数据的对齐关系决定的,理论上来说,从0到(inl+cipher_block_size-1)的任何一个数字都有可能(单位是字节),所以输出的参数out要有足够的空间存储数据。
写入到out中的实际数据长度保存在outl参数中。
操作成功返回1,否则返回0。
4.4EVP_EncryptFinal_ex
该函数处理最后(Final)的一段数据。
函数在padding功能打开的时候(缺省)才有效,这时候,它将剩余的最后的所有数据进行加密处理。
该算法使用标志的块padding方式(AKAPKCSpadding)。
加密后的数据写入到参数out里面,参数out的长度至少应该能够一个加密块。
写入的数据长度信息输入到outl参数里面。
该函数调用后,表示所有数据都加密完了,不应该再调用EVP_EncryptUpdate函数。
如果没有设置padding功能,那么本函数不会加密任何数据,如果还有剩余的数据,那么就会返回错误信息,也就是说,这时候数据总长度不是块长度的整数倍。
操作成功返回1,否则返回0。
PKCSpadding标准是这样定义的,在被加密的数据后面加上n个值为n的字节,使得加密后的数据长度为加密块长度的整数倍。
无论在什么情况下,都是要加上padding的,也就是说,如果被加密的数据已经是块长度的整数倍,那么这时候n就应该等于块长度。
比如,如果块长度是9,要加密的数据长度是11,那么5个值为5的字节就应该增加在数据的后面。
4.5EVP_DecryptInit_ex,EVP_DecryptUpdate和EVP_DecryptFinal_ex
这三个函数是上面三个函数相应的解密函数。
这些函数的参数要求基本上都跟上面相应的加密函数相同。
如果padding功能打开了,EVP_DecryptFinal会检测最后一段数据的格式,如果格式不正确,该函数会返回错误代码。
此外,如果打开了padding功能,EVP_DecryptUpdate函数的参数out的长度应该至少为(inl+cipher_block_size)字节;但是,如果加密块的长度为1,则其长度为inl字节就足够了。
三个函数都是操作成功返回1,否则返回0。
需要注意的是,虽然在padding功能开启的情况下,解密操作提供了错误检测功能,但是该功能并不能检测输入的数据或密钥是否正确,所以即便一个随机的数据块也可能无错的完成该函数的调用。
如果padding功能关闭了,那么当解密数据长度是块长度的整数倍时,操作总是返回成功的结果。
4.6EVP_CipherInit_ex,EVP_CipherUpdate和EVP_CipherFinal_ex
事实上,上面介绍的函数都是调用这三个函数实现的,它们是更底层的函数。
完成了数据的加密和解密功能。
他们根据参数enc决定执行加密还是解密操作,如果enc为1,则加密;如果enc为0,则解密;如果enc是-1,则不改变数据。
三个函数都是操作成功返回1,否则返回0。
4.7EVP_CIPHER_CTX_cleanup
该函数清除一个EVP_CIPHER_CTX结构中的所有信息并释放该结构占用的所有内存。
在使用上述的函数完成一个加密算法过程后应该调用该函数,这样可以避免一些敏感信息遗留在内存造成安全隐犯。
操作成功返回1,否则返回0。
4.8EVP_EncryptInit,EVP_DecryptInit和EVP_CipherInit
这三个函数的功能分别跟函数EVP_EncryptInit_e
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- openssl 系列 函数 api