openssl中添加新算法操作说明.docx
《openssl中添加新算法操作说明.docx》由会员分享,可在线阅读,更多相关《openssl中添加新算法操作说明.docx(17页珍藏版)》请在冰豆网上搜索。
![openssl中添加新算法操作说明.docx](https://file1.bdocx.com/fileroot1/2022-12/14/9d94e852-0f5a-4529-a665-bc823ad9dff7/9d94e852-0f5a-4529-a665-bc823ad9dff71.gif)
openssl中添加新算法操作说明
1.openssl简介
openssl是一个功能丰富且自包含的开源安全工具箱。
它提供的主要功能有:
SSL协议实现(包括SSLv2、SSLv3和TLSv1)、大量软算法(对称/非对称/摘要)、大数运算、非对称算法密钥生成、ASN.1编解码库、证书请求(PKCS10)编解码、数字证书编解码、CRL编解码、OCSP协议、数字证书验证、PKCS7标准实现和PKCS12个人数字证书格式实现等功能。
openssl采用C语言作为开发语言,这使得它具有优秀的跨平台性能。
openssl支持Linux、UNIX、windows、Mac等平台。
openssl目前最新的版本是openssl-1.0.1i。
2.问题描述
openssl中虽然集成了很多经典算法,对称算法、非对称算法、摘要算法等等,但有时候我们需要用到自定义的算法,比如要实现一个自定义的摘要算法,需要借助openssl带的大数库来实现,同时又希望将自己实现的算法封装到openssl里面,以便统一调用或者方便项目改造和替换。
最具现实意义的案例就是国密SM2等的改造。
本例将用国密中的摘要算法SM3作为添加对象,在windows下面进行编译调试,仅描述添加步骤,所以本文的前提是已经完成了基于openssl大数库的SM3的c语言实现。
3.具体步骤
3.1.准备工作
1、 下载openssl源码,openssl目前最新的版本是openssl-1.0.1i。
下载地址:
2、 sm3的c语言实现。
3、 windows下perl、vc的安装配置。
4、 熟悉openssl的编译过程。
3.2.SM3代码改造
涉及到的文件7个:
1、 新建文件sm3.h
这是最重要的一个头文件,里面定义了算法可以导出的算法,也就是里面声明的每一个函数最后都会生成对应的libeay.num(将在第五章中具体讲),能够导出到dll中供外部调用。
几个主要的声明如下:
定义sm3的摘要长度:
#defineSM3_DIGEST_LENGTH32 /*sm3摘要长度为256位32字节,md5的摘要长度128位notsure*/
定义SM3_CTX,这个结构其实就是对应evp封装中EVP_MD_CTX的md_data:
typedefstructSM3state_st
{
unsignedlonglongtotal_length;
unsignedcharmessage_buffer[64];
size_tmessage_buffer_position;
size_tV_i[8];
size_tV_i_1[8];
size_tT_j[64];
}SM3_CTX;
声明函数,包括init、update、final,这几个函数会在封装的时候被内部调用,当然在dll中导出了也可以外部调用:
intSM3_Init(SM3_CTX*c);
intSM3_Update(SM3_CTX*c,constvoid*data,size_tlen);
intSM3_Final(unsignedchar*md,SM3_CTX*c);
unsignedchar*SM3(unsignedchar*d,size_tn,unsignedchar*md);
2、 新建文件sm3_locl.h
这个头文件中包含一些要用到的宏定义。
主要定义了本算法实现中需要用到的内部函数,不能被导出到dll中供外部调用。
宏定义:
#ifndefROTATE
#defineROTATE(a,n)(((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
#endif
#defineEE(b,c,d)((b&c)|((~b)&d))
#defineFF(b,c,d)((((c)^(d))&(b))^(d))
#defineGG(b,c,d)(((b)&(c))|((b)&(d))|((c)&(d)))
#defineHH(b,c,d)((b)^(c)^(d))
#defineHH1(a)(a^(ROTATE(a,9))^(ROTATE(a,17)))
#defineHH2(a)(a^(ROTATE(a,15))^(ROTATE(a,23)))
内部函数:
voidinit_T_j(size_t*T_j);
voidinit_V_i(size_t*V_i);
voidCF(size_t*T_j,size_t*V_i,unsignedchar*B_i,size_t*V_i_1);
3、 新建文件sm3_dgst.c
实现sm3.h和sm3_locl中声明的函数,除了函数SM3(将在sm3_one.c中实现)。
4、 新建文件sm3_one.c
实现sm3.h中声明的函数SM3。
5、 新建文件sm3.c
实现对文件的摘要,如用在openssl作为命令行工具,文件名和摘要算法名作为选项参数实现使用算法对文件进行摘要。
6、 新建文件sm3test.c
算法的test文件。
7、 新建文件】Makefile
编译的Makefile文件。
里面描述在编译的时候以上的几个文件的角色、编译过程、依赖关系等。
3.3.EVP封装相关代码
涉及到的文件4个:
1、手动修改evp.h
evp在openssl里面的主要做的是封装的事情,因此首先在evp.h头文件中添加新算法sm3:
#ifndefOPENSSL_NO_SM3
constEVP_MD*EVP_sm3(void);
#endif
说明:
EVP_sm3()函数将返回返回一个sm3的EVP_MD的结构,这个结构以及EVP_sm3()函数都在m_sm3.c中定义。
2、新建文件m_sm3.c
这是放在EVP目录中关于新算法的一个重要文件,定义 sm3 的EVP_MD结构,EVP_MD结构原型在evp.h中:
sm3的EVP_MD结构:
staticconstEVP_MDsm3_md=
{
NID_sm3,//这个需要定义了OID之后生成,这个步骤在第四章。
NID_sm3WithRSAEncryption,//这个地方sm3WithRSA只做示例
SM3_DIGEST_LENGTH,//SM3的摘要长度,在sm3.h中定义
0,//flag
init,//结构中的init函数,指向自己声明在sm3.h中的SM3_Init
update,//同上
final,//同上
NULL,
NULL,
EVP_PKEY_RSA_method,//同上,只做示例
SM3_CBLOCK,//在sm3.h中声明
sizeof(EVP_MD*)+sizeof(SM3_CTX),
};
3、手动修改c_alld.c
openssl的算法封装之后使用时需要加载算法,实现SM3的添加:
#ifndefOPENSSL_NO_SM3
EVP_add_digest(EVP_sm3());
#endif
4、手动修改Makefile
将编译时候的LIBSRC、LIBOBJ中加入SM3新算法,并且添加sm3各种头文件的依赖关系。
3.4.OID生成
1、 涉及到的文件7个:
2、 手动修改objects.txt
添加sm3的OID,特别说明:
此处仅作示例,sm3的实际OID是:
rsadsi212:
SM3:
sm3
添加sm3WithRSAEncryption,这个是对应PKCS1的,只是为了让sm3的EVP_MD结构有值填充,实际添加sm3的本意不用于RSA,这里仅作示例。
pkcs115:
RSA-SM3:
sm3WithRSAEncryption
3、 执行命令自动更新obj_mac.h和obj_mac.num
打开cmd,切换到目录下源码的\crypto\objects\所在的目录下,
执行命令:
perlobjects.plobjects.txtobj_mac.numobj_mac.h
obj_mac.h和obj_mac.num这两个文件都会因为objects.txt的修改而更新。
增加的内容如:
4、 手动修改objects.h
将obj_mac.h中新增的内容同步到objects.h中。
(其实这一步不做也没有影响,因为之后不用这个文件来生成obj_dat.h。
objects.h的内容没有obj_mac.h的内容全面,千万不能用objects.h来obj_dat.h,一定要用obj_mac.h来生成才是正确的。
切记,血的教训!
)
5、 执行命令自动更新obj_dat.h
执行命令:
perlobj_dat.plobj_mac.hobj_dat.h
将会自动更新obj_dat.h这个文件,新增的内容如下:
注意看图上最后两排
Line4672:
921,/*OBJ_sm312840113549212*/
Line4843:
920,/*OBJ_sm3WithRSAEncryption128401135491115*/
最后带的一串数字本来是算法的OID,因为上面第2步的objects.txt中是乱填的,所以这个不是真实的OID。
仅作示例。
6、 手动修改 obj_xref.txt
添加:
sm3WithRSAEncryptionsm3rsaEncryption
7、 执行命令自动更新 obj_xref.h
执行命令:
perlobjxref.plobj_xref.txtobj_xref.h
obj_xref.h更新后的添加的内容如:
3.5.make相关设置
1、 涉及到的文件\util\下面5个:
2、 手动修改mkfiles.pl
添加:
"crypto/sm3",
添加上包含sm3的算法源码的目录,这个目录中包含sm3的Makefile文件。
之后就会按照Makefile进行编译。
3、 手动修改mkdef.pl
添加内容如图:
加上新算法的头文件等,可以在dll中导出算法函数。
4、 执行命令自动更新libeay.num
执行命令:
perlutil/mkdef.plcryptoupdate
Libeay.num更新后增加的内容如:
5、 手动修改mk1mf.pl
添加内容如:
6、 手动修改sp-diff.pl
添加内容如:
7、 涉及到的文件\crypto\下面2个:
8、 手动修改crypto-
添加内容如:
9、 手动修改install-
添加内容如:
10、 涉及到的文件根目录\下面5个:
11、 手动修改
添加内容如图:
Makefile、Makefile.bak、Makefile.org、、INSTALL.VMS
到这里,源码需要添加和修改的就结束了,下面将介绍编译和测试。
3.6.编译
1、 在cmd下,首先设置VC环境,执行VC目录下的vcvars32.BAT文件,如:
2、 cmd下进入openssl源码所在的目录,依次执行命令【编32位,如果64位可能缺ml64.exe】:
1)执行命令:
perlConfigureVC-WIN32no-asm
2) 执行命令:
ms\do_ms
3)执行命令:
nmake-fms\ntdll.mak:
这个是动态库:
如果编译成功,最后的输出都在out32dll目录下:
包括可执行文件、两个dll和两个lib文件【nmake-fms\nt.mak
这是静态库的编译命令,输出在out32目录下】。
编译成功如图:
4) 执行命令:
nmake-fms\ntdll.maktest
5)执行命令:
nmake-fms\ntdll.makinstall
七、测试
1、 API编程测试,在vs建工程,将openssl目录下生成的out32dll文件夹下的libeay32.dll和libeay32.lib到工程。
2、 设置工程的附加库和附加包含目录:
右键工程->属性->C/C++->常规->附加包含目录
右键工程->属性->链接器->常规->附加库目录
3、 sm3test.c源码如:
sm3test.c
#include
#include
#include
#pragmacomment(lib,"libeay32.lib")
staticsize_thash[8]={0};
voidout_hex(size_t*list1)
{
size_ti=0;
for(i=0;i<8;i++)
{
printf("%08x",list1[i]);
}
printf("\r\n");
}
main(intargc,char*argv[])
{
EVP_MD_CTXmdctx;
constEVP_MD*md;
charmess1[]="abc";
charmess2[]="abc";
unsignedcharmd_value[EVP_MAX_MD_SIZE];
intmd_len,i;
//使EVP_Digest系列函数支持所有有效的信息摘要算法
OpenSSL_add_all_digests();
argv[1]="sm3";
if(!
argv[1]){
printf("Usage:
mdtestdigestname\n");
exit
(1);
}
//根据输入的信息摘要函数的名字得到相应的EVP_MD算法结构
md=EVP_get_digestbyname(argv[1]);
//md=EVP_sm3();
if(!
md){
printf("Unknownmessagedigest%s\n",argv[1]);
exit
(1);
}
//初始化信息摘要结构mdctx,这在调用EVP_DigestInit_ex函数的时候是必须的。
EVP_MD_CTX_init(&mdctx);
//使用md的算法结构设置mdctx结构,impl为NULL,即使用缺省实现的算法(openssl本身提供的信息摘要算法)
EVP_DigestInit_ex(&mdctx,md,NULL);
//开始真正进行信息摘要运算,可以多次调用该函数,处理更多的数据,这里只调用了两次
EVP_DigestUpdate(&mdctx,mess1,strlen(mess1));
//EVP_DigestUpdate(&mdctx,mess2,strlen(mess2));
//完成信息摘要计算过程,将完成的摘要信息存储在md_value里面,长度信息存储在md_len里面
EVP_DigestFinal_ex(&mdctx,md_value,&md_len);
//使用该函数释放mdctx占用的资源,如果使用_ex系列函数,这是必须调用的。
EVP_MD_CTX_cleanup(&mdctx);
printf("Digestis:
");
for(i=0;iprintf("\n");
//SM3("abc",3,hash);
//out_hex(hash);
system("pause");
}
intmain1(intargc,char*argv[])
{
SM3_CTX*c=(SM3_CTX*)malloc(sizeof(SM3_CTX));
SM3_Init(c);
//SM3_Final_dword(hash,c);
SM3_Update(c,"abc",3);
SM3_Final(hash,c);
out_hex(hash);
//66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
SM3_Init(c);
SM3_Update(c,"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",64);
/*for(i=0;i<16;i++){
SM3_Update(c,"abcd",4);
}*/
SM3_Final(hash,c);
out_hex(hash);
//debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732
//SM3("abc",3,hash);
//out_hex(hash);
system("pause");
return0;
}
4、 sm3test.c运行使用sm3算法对“abc”进行摘要后的结果如图:
和国密标准的附录示例一致: