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。

很多其它的相关知识请參阅铺天盖地的各种官方非官方文档。今天来实现如何将一个新算法加入进openssl中。

问题描写叙述

openssl中尽管集成了非常多经典算法,对称算法、非对称算法、摘要算法等等,但有时候我们须要用到自己定义的算法,比方要实现一个自己定义的摘要算法,须要借助openssl带的大数库来实现,同一时候又希望将自己实现的算法封装到openssl里面,以便统一调用或者方便项目改造和替换。最具现实意义的案例就是国密SM2等的改造。本例将用国密中的摘要算法SM3作为加入对象,在windows以下进行编译调试,仅描写叙述加入步骤,所以本文的前提是已经完毕了基于openssl大数库的SM3的c语言实现。本文仅供依葫芦画瓢,要理解原理请自行查阅别的资料或者自己解读源代码,或者等我的下一篇文章。

详细步骤

一、准备工作

1、  下载openssl源代码,openssl眼下最新的版本号是openssl-1.0.1i。下载地址:

2、  sm3的c语言实现。

3、  windows下perl、vc的安装配置。

4、  熟悉openssl的编译过程。

二、SM3代码改造【这个步骤涉及到的文件所有新建,存放文件夹关系如图】

1、  涉及到的文件7个:

1、  【新建文件】sm3.h

这是最重要的一个头文件,里面定义了算法可以导出的算法,也就是里面声明的每个函数最后都会生成相应的libeay.num(将在第五章中详细讲),可以导出到dll中供外部调用。几个基本的声明例如以下:

定义sm3的摘要长度:

#define SM3_DIGEST_LENGTH 32    /* sm3 摘要长度为256位 32字节,md5的摘要长度128位 not sure*/

定义SM3_CTX,这个结构事实上就是相应evp封装中EVP_MD_CTX的md_data:

typedef struct SM3state_st
{
unsigned long long total_length;
unsigned char message_buffer[64];
size_t message_buffer_position;
size_t V_i[8];
size_t V_i_1[8];
size_t T_j[64];
} SM3_CTX;

声明函数,包含init、update、final,这几个函数会在封装的时候被内部调用,当然在dll中导出了也能够外部调用:

int SM3_Init(SM3_CTX*c);
intSM3_Update(SM3_CTX *c, const void *data, size_t len);
intSM3_Final(unsigned char *md, SM3_CTX *c);
unsignedchar *SM3(unsigned char *d, size_t n, unsigned char *md);

2、  【新建文件】sm3_locl.h

这个头文件里包括一些要用到的宏定义。主要定义了本算法实现中须要用到的内部函数,不能被导出到dll中供外部调用。

宏定义:

#ifndefROTATE
#defineROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
#endif #define EE(b,c,d) ((b & c) | ((~ b) & d))
#define FF(b,c,d) ((((c)^ (d)) & (b)) ^ (d))
#define GG(b,c,d) (((b)& (c)) | ((b) & (d)) | ((c) & (d)))
#define HH(b,c,d) ((b)^ (c) ^ (d))
#define HH1(a) (a^ (ROTATE(a, 9)) ^ (ROTATE(a, 17)))
#define HH2(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, unsigned char *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文件。里面描写叙述在编译的时候以上的几个文件的角色、编译过程、依赖关系等。

三、EVP封装相关代码

1、  涉及到的文件4个:

2、  【手动改动】evp.h

evp在openssl里面的主要做的是封装的事情,因此首先在evp.h头文件里加入新算法sm3:

#ifndef OPENSSL_NO_SM3
const EVP_MD *EVP_sm3(void);
#endif

说明:EVP_sm3()函数将返回返回一个sm3的EVP_MD的结构,这个结构以及EVP_sm3()函数都在m_sm3.c中定义。

3、  【新建文件】m_sm3.c

这是放在EVP文件夹中关于新算法的一个关键文件,定义sm3的EVP_MD结构,EVP_MD结构原型在evp.h中:

sm3的EVP_MD结构:

static const EVP_MD sm3_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),
};

4、  【手动改动】c_alld.c

openssl的算法封装之后使用时须要载入算法,实现SM3的加入:

#ifndefOPENSSL_NO_SM3
EVP_add_digest(EVP_sm3());
#endif

5、  【手动改动】Makefile

将编译时候的LIBSRC、LIBOBJ中加入SM3新算法,而且加入sm3各种头文件的依赖关系。

四、OID生成

1、  涉及到的文件7个:

2、  【手动改动】objects.txt

加入sm3的OID,特别说明:此处仅作演示样例,sm3的实际OID是:

rsadsi 2 12                 :SM3                           : sm3

加入sm3WithRSAEncryption,这个是相应PKCS1的,仅仅是为了让sm3的EVP_MD结构有值填充,实际加入sm3的本意不用于RSA,这里仅作演示样例。

pkcs1 15           : RSA-SM3                           : sm3WithRSAEncryption

3、  【运行命令自己主动更新】obj_mac.h和obj_mac.num

打开cmd,切换到文件夹下源代码的\crypto\objects\所在的文件夹下,

运行命令:perl objects.pl objects.txt obj_mac.num obj_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

运行命令:perl obj_dat.pl obj_mac.h obj_dat.h

将会自己主动更新obj_dat.h这个文件,新增的内容例如以下:

注意看图上最后两排

Line 4672: 921,	/* OBJ_sm3                          1 2 840 113549 2 12 */
Line 4843: 920, /* OBJ_sm3WithRSAEncryption 1 2 840 113549 1 1 15 */

最后带的一串数字本来是算法的OID,由于上面第2步的objects.txt中是乱填的,所以这个不是真实的OID。仅作演示样例。

6、  【手动改动】obj_xref.txt

加入:

sm3WithRSAEncryption	sm3	rsaEncryption

7、  【运行命令自己主动更新】obj_xref.h

运行命令:perl objxref.pl obj_xref.txt obj_xref.h

obj_xref.h更新后的加入的内容如:

五、make相关设置

1、  涉及到的文件\util\以下5个:

2、  【手动改动】mkfiles.pl

加入:

"crypto/sm3",

加入上包括sm3的算法源代码的文件夹,这个文件夹中包括sm3的Makefile文件。之后就会依照Makefile进行编译。

3、  【手动改动】mkdef.pl

加入内容如图:

加上新算法的头文件等,能够在dll中导出算法函数。

4、  【运行命令自己主动更新】libeay.num

运行命令:perl util/mkdef.pl crypto update

Libeay.num更新后添加的内容如:

5、  【手动改动】mk1mf.pl

加入内容如:

6、  【手动改动】sp-diff.pl

加入内容如:

7、  涉及到的文件\crypto\以下2个:

8、  【手动改动】crypto-lib.com

加入内容如:

9、  【手动改动】install-crypto.com

加入内容如:

10、  涉及到的文件根文件夹\以下5个:

11、  【手动改动】

加入内容如图:Makefile、Makefile.bak、Makefile.org、makevms.com、INSTALL.VMS

到这里,源代码须要加入和改动的就结束了,以下将介绍编译和測试。

六、编译

1、  在cmd下,首先设置VC环境,运行VC文件夹下的vcvars32.BAT文件,如:

2、  cmd下进入openssl源代码所在的文件夹,依次运行命令【编32位,假设64位可能缺ml64.exe】:

1)运行命令:perl Configure VC-WIN32 no-asm

2)  运行命令:ms\do_ms

3)运行命令:nmake-f ms\ntdll.mak:这个是动态库:假设编译成功,最后的输出都在out32dll文件夹下: 包含可运行文件 、两个dll和两个lib文件【nmake -fms\nt.mak

这是静态库的编译命令,输出在out32文件夹下】。编译成功如图:

4)  运行命令:nmake -fms\ntdll.mak test

5)运行命令:nmake -f ms\ntdll.mak install

七、測试

1、  API编程測试,在vs建project,将openssl文件夹下生成的out32dll文件夹下的libeay32.dll和libeay32.lib到project。

2、  设置project的附加库和附加包括文件夹:

右键project->属性-> C/C++ ->常规->附加包括文件夹

右键project->属性-> 链接器 ->常规->附加库文件夹

3、  sm3test.c源代码如:

sm3test.c

#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/sm3.h>
#pragma comment(lib, "libeay32.lib")
static size_t hash[8] = {0}; void out_hex(size_t *list1)
{
size_t i = 0;
for (i = 0; i < 8; i++)
{
printf("%08x ", list1[i]);
}
printf("\r\n");
} main(int argc, char *argv[])
{
EVP_MD_CTX mdctx;
const EVP_MD *md;
char mess1[] = "abc";
char mess2[] = "abc";
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_len, i;
//使EVP_Digest系列函数支持全部有效的信息摘要算法
OpenSSL_add_all_digests(); argv[1] = "sm3"; if(!argv[1]) {
printf("Usage: mdtest digestname\n");
exit(1);
}
//依据输入的信息摘要函数的名字得到对应的EVP_MD算法结构
md = EVP_get_digestbyname(argv[1]);
//md = EVP_sm3(); if(!md) {
printf("Unknown message digest %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("Digest is: ");
for(i = 0; i < md_len; i++) printf("%02x", md_value[i]);
printf("\n"); //SM3("abc",3,hash);
//out_hex(hash); system("pause");
} int main1(int argc, 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);
//66c7f0f4 62eeedd9 d1f2d46b dc10e4e2 4167c487 5cf2f7a2 297da02b 8f4ba8e0 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);
//debe9ff9 2275b8a1 38604889 c18e5a4d 6fdb70e5 387e5765 293dcba3 9c0c5732 //SM3("abc",3,hash);
//out_hex(hash);
system("pause");
return 0;
}

4、  sm3test.c执行使用sm3算法对“abc”进行摘要后的结果如图:

和国密标准的附录演示样例一致:

八、总结

本例以摘要算法为例,详细介绍了一下通过直接加入源代码的方式如何在openssl里面加入新算法,而非engine方式。当然假设觉得engine方式更方便,则请忽略本文。本文仅仅是在描写叙述怎么做,可是没有讲为什么。由于比如openssl本身的封装机制是须要解读源代码才干更好地理解上述文中为什么须要做那些步骤,由于这些步骤已经够复杂了,所以解读源代码将另起一篇文章。本文仅供依葫芦画瓢,要理解原理请自行查阅别的资料或者自己解读源代码,或者等我的下一篇文章。

不论什么疑问或者指正请联系我,谢谢!

小伙伴们加油!GOOD LUCK!



源代码方式向openssl中加入新算法完整具体步骤(演示样例:摘要算法SM3)【非engine方式】的更多相关文章

  1. 让你提前认识软件开发(19):C语言中的协议及单元測试演示样例

    第1部分 又一次认识C语言 C语言中的协议及单元測试演示样例 [文章摘要] 在实际的软件开发项目中.常常要实现多个模块之间的通信.这就须要大家约定好相互之间的通信协议,各自依照协议来收发和解析消息. ...

  2. JSP中文件的上传于下载演示样例

    一.文件上传的原理     1.文件上传的前提:         a.form表单的method必须是post         b.form表单的enctype必须是multipart/form-da ...

  3. Libcurl的编译_HTTP/HTTPSclient源代码演示样例

    HTTP/HTTPSclient源代码演示样例 环境:  zlib-1.2.8  openssl-1.0.1g  curl-7.36 Author:  Kagula LastUpdateDate: 2 ...

  4. c#Winform程序的toolStripButton自己定义背景应用演示样例源代码

    C# Winform程序的toolStrip中toolStripButton的背景是蓝色的,怎样改变背景及边框的颜色和样式呢? 实现此功能须要重写toolStripButton的Paint方法 这里仅 ...

  5. Android中MVP模式与MVC模式比較(含演示样例)

    原文链接 http://sparkyuan.me/ 转载请注明出处 MVP 介绍 MVP模式(Model-View-Presenter)是MVC模式的一个衍生. 主要目的是为了解耦,使项目易于维护. ...

  6. 【COCOS2D-HTML5 开发之三】演示样例项目附源代码及执行的GIF效果图

    本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/cocos2d- ...

  7. C++ Primer中文本查询演示样例Query的实现

    近期在看C++ Primer复习C++的语法,看到书中15.9章中的文本查询演示样例时,认为设计得非常不错,于是便动手照着实现了一个,改动了非常久最终执行成功了,从中也学习到了非常多的语法.以下把实现 ...

  8. SNF快速开发平台MVC-各种级联绑定方式,演示样例程序(包含表单和表格控件)

    做了这么多项目,经常会使用到级联.联动的情况. 如:省.市.县.区.一级分类.二级分类.三级分类.仓库.货位. 方式:有表单需要做级联的,还是表格行上需要做级联操作的. 实现:实现方法也有很多种方式. ...

  9. 01_MUI之Boilerplate中:HTML5演示样例,动态组件,自己定义字体演示样例,自己定义字体演示样例,图标字体演示样例

     1安装HBuilder5.0.0,安装后的界面截图例如以下: 2 依照https://www.muicss.com/docs/v1/css-js/boilerplate-html中的说明,创建上 ...

随机推荐

  1. CodeIgniter实现读写分离

    http://pengbotao.cn/codeigniter-mysql-proxy.html

  2. zoj 2830 Champion of the Swordsmanship

    Champion of the Swordsmanship Time Limit: 2 Seconds      Memory Limit: 65536 KB In Zhejiang Universi ...

  3. hdu2074

    我先求出交叉的gird,然后再一行一行求得.感觉还可以吧.思路比较清晰,开始想的是数是第几行然后从每一行的前后开始控制,好麻烦的感觉,我就先求出来了框架再做就好做多啦!后来PE,突然发现我特殊处理n= ...

  4. [SCOI2005]最大子矩阵 (动态规划)

    题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 输入格式: 第一行为n,m,k(1≤n≤100,1≤m≤2 ...

  5. 【2018.9.20】JOI 2017 Final T3「JOIOI 王国 / The Kingdom of JOIOI」

    题目链接 题目描述 JOIOI 王国是一个 $H$ 行 $W$ 列的长方形网格,每个 $1\times 1$ 的子网格都是一个正方形的小区块.为了提高管理效率,我们决定把整个国家划分成两个省 $JOI ...

  6. angular实时显示checkbox被选中的元素

    /** * Created by zh on 20/05/15. */ // Code goes here var iApp = angular.module("App", []) ...

  7. poj 3311 状压dp 最短路

    C - Hie with the Pie Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64 ...

  8. msp430项目编程47

    msp430综合项目---有线采集传输平台系统47 1.电路工作原理 2.代码(显示部分) 3.代码(功能实现) 4.项目总结

  9. R语言入门--画图(一)--ggplot2

    先写一些需要用到的知识点,比如包.函数 dplyr 很好用的包 经常与ggplot2连用 mutate:用于对数据框的列进行重新处理,或者用处理的结果添加新列 数据清洗: 1.na.omit()   ...

  10. Mongodb报错:ERROR: child process failed, exited with error number 1

    Mongodb在启动时报错: 2018-10-16T11:18:54.533+0800 I CONTROL [main] Automatically disabling TLS 1.0, to for ...