OpenSSL中对称加密算法的统一接口详解.docx
- 文档编号:2020706
- 上传时间:2023-05-02
- 格式:DOCX
- 页数:13
- 大小:19.49KB
OpenSSL中对称加密算法的统一接口详解.docx
《OpenSSL中对称加密算法的统一接口详解.docx》由会员分享,可在线阅读,更多相关《OpenSSL中对称加密算法的统一接口详解.docx(13页珍藏版)》请在冰点文库上搜索。
OpenSSL中对称加密算法的统一接口详解
2.EVP接口
2.1数据结构
Openssl/crypto/evp目录下定义各种算法的接口源文件,这些文件要作的事就是要填写描述算法的EVP_CIPHER结构,每个算法都有一个EVP_CIPHER结构进行描述:
Openssl/crypto/evp/evp.h
structevp_cipher_st
{
intnid;
intblock_size;
intkey_len;/*Defaultvalueforvariablelengthciphers*/
intiv_len;
unsignedlongflags;/*Variousflags*/
int(*init)(EVP_CIPHER_CTX*ctx,constunsignedchar*key,
constunsignedchar*iv,intenc);/*initkey*/
int(*do_cipher)(EVP_CIPHER_CTX*ctx,unsignedchar*out,
constunsignedchar*in,unsignedintinl);/*encrypt/decryptdata*/
int(*cleanup)(EVP_CIPHER_CTX*);/*cleanupctx*/
intctx_size;/*howbigctx->cipher_dataneedstobe*/
int(*set_asn1_parameters)(EVP_CIPHER_CTX*,ASN1_TYPE*);/*PopulateaASN1_TYPEwithparameters*/
int(*get_asn1_parameters)(EVP_CIPHER_CTX*,ASN1_TYPE*);/*GetparametersfromaASN1_TYPE*/
int(*ctrl)(EVP_CIPHER_CTX*,inttype,intarg,void*ptr);/*Miscellaneousoperations*/
void*app_data;/*Applicationdata*/
}/*EVP_CIPHER*/;
typedefstructevp_cipher_stEVP_CIPHER;
nid:
算法的ID号,在include/openssl/object.h中定义;
block_size:
加解密的分组长度
key_len:
密钥长度
iv_len:
初始向量长度
flags:
标志
(*init):
初始化函数,提供密钥,IV向量,算法上下文CTX,加密还是解密
(*do_cipher):
加解密函数,提供算法上下文CTX,输出数据,输入数据和输入数据长度
(*clean_up):
资源释放
ctx_size:
各算法相关数据大小,实际就是各算法的密钥数据
(*set_asn1_parameters):
设置asn1参数
(*get_asn1_parameters):
获取asn1参数
(*ctrl):
其他控制操作
app_data:
算法相关数据
另一个重要的数据结构是描述加密算法的上下文结构EVP_CIPHER_CTX,这个结构是进入算法前由系统根据指定的算法提供的:
structevp_cipher_ctx_st
{
constEVP_CIPHER*cipher;
ENGINE*engine;/*functionalreferenceif'cipher'isENGINE-provided*/
intencrypt;/*encryptordecrypt*/
intbuf_len;/*numberwehaveleft*/
unsignedcharoiv[EVP_MAX_IV_LENGTH];/*originaliv*/
unsignedchariv[EVP_MAX_IV_LENGTH];/*workingiv*/
unsignedcharbuf[EVP_MAX_BLOCK_LENGTH];/*savedpartialblock*/
intnum;/*usedbycfb/ofbmode*/
void*app_data;/*applicationstuff*/
intkey_len;/*Maychangeforvariablelengthcipher*/
unsignedlongflags;/*Variousflags*/
void*cipher_data;/*perEVPdata*/
intfinal_used;
intblock_mask;
unsignedcharfinal[EVP_MAX_BLOCK_LENGTH];/*possiblefinalblock*/
}/*EVP_CIPHER_CTX*/;
typedefstructevp_cipher_ctx_stEVP_CIPHER_CTX;
参数为:
cipher:
算法指针
engine:
加解密引擎
encrypt:
加密或解密
buf_len:
剩余空间
oiv:
原始的初始向量
iv:
当前的初始向量
buf:
保存的部分块数据
num:
cfb/ofb方式时的数据数量
app_data:
应用相关数据
key_len:
密钥长度
flags:
标志
cipher_data:
各算法相关部分,主要是各算法的key等
final_used:
block_mask:
块的掩码
final:
最后的分组块
1.2.2算法接口
每种算法就是要填写各自的EVP_CIPHER结构,以RC4为例,定义了两个RC4的EVP_CIPHER结构,只是密钥长度不同,一个是128位(16字节密钥),一个是40位(5字节密钥),而算法都一样:
#ifndefOPENSSL_NO_RC4
#include
#include"cryptlib.h"
#include
#include
#include
/*FIXME:
surelythisisavailableelsewhere?
*/
#defineEVP_RC4_KEY_SIZE16
//这个结构是各加密算法独有的,各算法的各自不同
//也就是EVP_CIPHER_CTX结构中cipher_data
typedefstruct
{
RC4_KEYks;/*workingkey*/
}EVP_RC4_KEY;
#definedata(ctx)((EVP_RC4_KEY*)(ctx)->cipher_data)
staticintrc4_init_key(EVP_CIPHER_CTX*ctx,constunsignedchar*key,
constunsignedchar*iv,intenc);
staticintrc4_cipher(EVP_CIPHER_CTX*ctx,unsignedchar*out,
constunsignedchar*in,unsignedintinl);
staticconstEVP_CIPHERr4_cipher=
{
NID_rc4,
1,EVP_RC4_KEY_SIZE,0,
EVP_CIPH_VARIABLE_LENGTH,
rc4_init_key,
rc4_cipher,
NULL,
sizeof(EVP_RC4_KEY),
NULL,
NULL,
NULL
};
staticconstEVP_CIPHERr4_40_cipher=
{
NID_rc4_40,
1,5/*40bit*/,0,
EVP_CIPH_VARIABLE_LENGTH,
rc4_init_key,
rc4_cipher,
NULL,
sizeof(EVP_RC4_KEY),
NULL,
NULL,
NULL
};
//返回算法结构指针
constEVP_CIPHER*EVP_rc4(void)
{
return(&r4_cipher);
}
constEVP_CIPHER*EVP_rc4_40(void)
{
return(&r4_40_cipher);
}
//密钥初始化函数
//ctx:
加解密上下文;key:
密钥字符串;iv:
初始化向量;enc:
加密还是解密
staticintrc4_init_key(EVP_CIPHER_CTX*ctx,constunsignedchar*key,
constunsignedchar*iv,intenc)
{
//RC4算法设置密钥函数
//一般来说,加解密时算法里用的密钥并不是用户输入的密码字符串本身,因为算法
//使用的密钥长度要求是固定的,通常为64位或128位,而用户自己定义的密码长度
//则不确定,所以一般都都要对用户输入的密码进行变换,映射到一个固定长度密钥
//上,然后算法再使用该密钥加密,所以算法中用的密钥和用户的密码一般是不同的
RC4_set_key(&data(ctx)->ks,EVP_CIPHER_CTX_key_length(ctx),
key);
return1;
}
//加解密处理函数
//ctx:
加解密上下文;out:
输出数据;in:
输入数据;inl:
输入数据长度
staticintrc4_cipher(EVP_CIPHER_CTX*ctx,unsignedchar*out,
constunsignedchar*in,unsignedintinl)
{
RC4(&data(ctx)->ks,inl,in,out);
return1;
}
#endif
对于定义好EVP_CIPHER结构的加解密算法,最后通过EVP_add_cipher()函数添加到系统算法链表中:
openssl/evp/c_alle.c
voidOpenSSL_add_all_ciphers(void)
{
......
#ifndefOPENSSL_NO_RC4
EVP_add_cipher(EVP_rc4());
EVP_add_cipher(EVP_rc4_40());
#endif
......
以后外部函数要调用RC4算法,实际就是找到RC4的EVP_CIPHER结构指针,进行初始化后进行加解密处理:
如openssl命令:
opensslenc–rc4–inaaa.txt–outaaa.enc
执行顺序如下:
openssl/apps/openssl.c
main()->do_cmd()->MAIN()(apps/enc.c)->EVP_get_cipherbyname(),EVP_BytesToKey(),BIO_set_cipher(),
BIO_set_cipher->EVP_CipherInit_ex->ctx->cipher->init
而加密算法作为BIO的一个环节被BIO_push到BIO中,这样就通过直接BIO读写操作就调用了相应的加解密算法。
3.块加密算法定义宏
对于块加密算法,如AES、CAST、Blowfish等,其加解密函数都是类似的,openssl更是定义了一系列宏来简化算法的定义,如对于Blowfish算法接口:
/*openssl/evp/e_bf.c*/
#ifndefOPENSSL_NO_BF
#include
#include"cryptlib.h"
#include
#include"evp_locl.h"
#include
#include
staticintbf_init_key(EVP_CIPHER_CTX*ctx,constunsignedchar*key,
constunsignedchar*iv,intenc);
typedefstruct
{
BF_KEYks;
}EVP_BF_KEY;
#definedata(ctx)EVP_C_DATA(EVP_BF_KEY,ctx)
//定义块加密算法的宏
IMPLEMENT_BLOCK_CIPHER(bf,ks,BF,EVP_BF_KEY,NID_bf,8,16,8,64,
EVP_CIPH_VARIABLE_LENGTH,bf_init_key,NULL,
EVP_CIPHER_set_asn1_iv,EVP_CIPHER_get_asn1_iv,NULL)
//显式只需要定义一个初始化密钥函数就可以了
staticintbf_init_key(EVP_CIPHER_CTX*ctx,constunsignedchar*key,
constunsignedchar*iv,intenc)
{
BF_set_key(&data(ctx)->ks,EVP_CIPHER_CTX_key_length(ctx),key);
return1;
}
#endif
在openssl/evp/evp_locl.h中该宏定义为:
#defineIMPLEMENT_BLOCK_CIPHER(cname,ksched,cprefix,kstruct,nid,\
block_size,key_len,iv_len,cbits,\
flags,init_key,\
cleanup,set_asn1,get_asn1,ctrl)\
BLOCK_CIPHER_all_funcs(cname,cprefix,cbits,kstruct,ksched)\
BLOCK_CIPHER_defs(cname,kstruct,nid,block_size,key_len,iv_len,\
cbits,flags,init_key,cleanup,set_asn1,\
get_asn1,ctrl)
1)宏BLOCK_CIPHER_all_funcs用来定义加解密函数,定义为:
#defineBLOCK_CIPHER_all_funcs(cname,cprefix,cbits,kstruct,ksched)\
BLOCK_CIPHER_func_cbc(cname,cprefix,kstruct,ksched)\
BLOCK_CIPHER_func_cfb(cname,cprefix,cbits,kstruct,ksched)\
BLOCK_CIPHER_func_ecb(cname,cprefix,kstruct,ksched)\
BLOCK_CIPHER_func_ofb(cname,cprefix,cbits,kstruct,ksched)
其中BLOCK_CIPHER_func_cbc定义为:
#defineBLOCK_CIPHER_func_cbc(cname,cprefix,kstruct,ksched)\
staticintcname##_cbc_cipher(EVP_CIPHER_CTX*ctx,unsignedchar*out,constunsignedchar*in,unsignedintinl)\
{\
cprefix##_cbc_encrypt(in,out,(long)inl,&((kstruct*)ctx->cipher_data)->ksched,ctx->iv,ctx->encrypt);\
return1;\
}
此处注意一个#define的技巧:
可以用#define替换变量或函数名,参数在打头或结尾处时,可分别在参数后或参数前用##;参数在中间,参数开头结尾都用##;
这样对于blowfish定义来说,上面这个宏实际定义这样一个函数:
staticintbf_cbc_cipher(EVP_CIPHER_CTX*ctx,unsignedchar*out,constunsignedchar*in,unsignedintinl)
{
bf_cbc_encrypt(in,out,(long)inl,&((kstruct*)ctx->cipher_data)->ksched,ctx->iv,ctx->encrypt);
return1;
}
其他几个宏定义类似,定义不同模式的bf加密算法,包括cbc,cfb,ecb,ofb。
2)宏BLOCK_CIPHER_defs用于定义算法结构,定义为:
#defineBLOCK_CIPHER_defs(cname,kstruct,\
nid,block_size,key_len,iv_len,cbits,flags,\
init_key,cleanup,set_asn1,get_asn1,ctrl)\
BLOCK_CIPHER_def_cbc(cname,kstruct,nid,block_size,key_len,iv_len,flags,\
init_key,cleanup,set_asn1,get_asn1,ctrl)\
BLOCK_CIPHER_def_cfb(cname,kstruct,nid,key_len,iv_len,cbits,\
flags,init_key,cleanup,set_asn1,get_asn1,ctrl)\
BLOCK_CIPHER_def_ofb(cname,kstruct,nid,key_len,iv_len,cbits,\
flags,init_key,cleanup,set_asn1,get_asn1,ctrl)\
BLOCK_CIPHER_def_ecb(cname,kstruct,nid,block_size,key_len,iv_len,flags,\
init_key,cleanup,set_asn1,get_asn1,ctrl)
其中BLOCK_CIPHER_def_cbc定义为:
#defineBLOCK_CIPHER_def_cbc(cname,kstruct,nid,block_size,key_len,\
iv_len,flags,init_key,cleanup,set_asn1,\
get_asn1,ctrl)\
BLOCK_CIPHER_def1(cname,cbc,cbc,CBC,kstruct,nid,block_size,key_len,\
iv_len,flags,init_key,cleanup,set_asn1,get_asn1,ctrl)
而BLOCK_CIPHER_def1定义为:
#defineBLOCK_CIPHER_def1(cname,nmode,mode,MODE,kstruct,nid,block_size,\
key_len,iv_len,flags,init_key,cleanup,\
set_asn1,get_asn1,ctrl)\
staticconstEVP_CIPHERcname##_##mode={\
nid##_##nmode,block_size,key_len,iv_len,\
flags|EVP_CIPH_##MODE##_MODE,\
init_key,\
cname##_##mode##_cipher,\
cleanup,\
sizeof(kstruct),\
set_asn1,get_asn1,\
ctrl,\
NULL\
};\
constEVP_CIPHER*EVP_##cname##_##mode(void){return&cname##_##mode;}
所以宏BLOCK_CIPHER_def_cbc展开后就是blowfish的cbc算法结构定义:
staticconstEVP_CIPHERbf_cbc={
NID_bf_cbc,8,16,8,
EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_CBC_MODE,
bf_init_key,
bf_cbc_cipher,
NULL,
sizeof(EVP_BF_KEY),
EVP_CIPHER_set_asn1_iv,EVP_CIPHER_get_asn1_iv,
NULL,
NULL
};
constEVP_CIPHER*EVP_bf_cbc(void){return&bf_cbc;}
其他几个宏定义类似,定义不同模式的bf加密算法的EVP_CIPHER数据结构,包括cbc,cfb,ecb,ofb。
4.结论
openssl使用了统一的EVP_CIPHER算法结构,很好地封装了各种对称加密算法,实现了算法的对象化。
5.附录
cbc,cfb,ecb,ofb等并不是新的加密算法,而是对加密算法的应用模式。
ECB:
ElectronicCodeBook,电子密码本模式,最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。
CBC:
CipherBlockChaining,密码分组链接,明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。
CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
CFB:
CipherFeedBack,密码反馈,类似于自同步序列密码,分组加密后,按8位分组将密文和明文进行移位异或后得到输出同时反馈回移位寄存器,优点最小可以按字节进行加解密,也可以是n位的,CFB也是上下文相关的,CFB模式下,明文的一个错误会影响后面的密文(错误扩散)。
OFB:
OutputFeedback,输出反馈,将分组密码作为同步序列密码运行,和CFB相似,不过OFB用的是前一个n位密文输出分组反馈回移位寄存器,OFB没有错误扩散问题。
(T002)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- OpenSSL 对称 加密算法 统一 接口 详解