openssl+EVP详解

EVP(Enveloped Public Key)是 OpenSSL 中用于提供对称加密、非对称加密和哈希功能的高级加密接口。EVP 库提供了一个抽象的加密框架,使得可以在不同的算法实现之间进行切换,而不需要改变应用程序的代码。以下是一些 EVP 开发的主要方面:

一、EVP基本介绍

1. EVP 加密和解密

EVP 提供了通用的加密和解密函数,可以用于对称加密和非对称加密。一般的流程如下:

  • 选择加密算法,创建相应的 EVP_CIPHER 结构。
  • 初始化 EVP_CIPHER_CTX 上下文。
  • 使用 EVP_EncryptInit_exEVP_DecryptInit_ex 初始化加密或解密操作。
  • 使用 EVP_EncryptUpdateEVP_DecryptUpdate 处理数据。
  • 使用 EVP_EncryptFinal_exEVP_DecryptFinal_ex 完成加密或解密操作。
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = EVP_aes_256_cbc();ctx = EVP_CIPHER_CTX_new();EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, plaintext_len);
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);EVP_CIPHER_CTX_free(ctx);

2. EVP 签名和验证

EVP 提供了通用的签名和验证函数,可以用于不同的哈希算法和签名算法。一般的流程如下:

  • 选择哈希算法和签名算法,创建相应的 EVP_MDEVP_PKEY 结构。
  • 初始化 EVP_MD_CTX 上下文。
  • 使用 EVP_DigestInit_ex 初始化哈希操作。
  • 使用 EVP_DigestUpdate 处理数据。
  • 使用 EVP_DigestFinal_ex 完成哈希操作。
  • 使用 EVP_SignInit_exEVP_VerifyInit_ex 初始化签名或验证操作。
  • 使用 EVP_SignUpdateEVP_VerifyUpdate 处理数据。
  • 使用 EVP_SignFinalEVP_VerifyFinal 完成签名或验证操作。
EVP_MD_CTX *mdctx;
const EVP_MD *md = EVP_sha256();
EVP_PKEY *pkey;
unsigned char signature[256];
size_t sig_len;mdctx = EVP_MD_CTX_new();
pkey = load_private_key();EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, data, data_len);
EVP_DigestFinal_ex(mdctx, digest, &digest_len);EVP_SignInit_ex(mdctx, EVP_sha256(), NULL);
EVP_SignUpdate(mdctx, data, data_len);
EVP_SignFinal(mdctx, signature, &sig_len, pkey);EVP_MD_CTX_free(mdctx);

3. EVP 加解密文件

EVP 还提供了一些便捷的函数用于对文件进行加解密操作,例如 EVP_EncryptInit_exEVP_DecryptUpdateEVP_EncryptFinal_ex 等。

EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = EVP_aes_256_cbc();ctx = EVP_CIPHER_CTX_new();EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, plaintext_len);
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);EVP_CIPHER_CTX_free(ctx);

这些是 EVP 库的一些基本用法。具体的使用取决于你的需求,可以根据 OpenSSL 的文档和示例代码进一步了解。

二、源码结构

evp源码位于crypto/evp目录,可以分为如下几类:

2.1 全局函数

主要包括c_allc.c、c_alld.c、c_all.c以及names.c。他们加载openssl支持的所有的对称算法和摘要算法,放入到哈希表中。实现了OpenSSL_add_all_digests、OpenSSL_add_all_ciphers以及OpenSSL_add_all_algorithms(调用了前两个函数)函数。在进行计算时,用户也可以单独加载摘要函数(EVP_add_digest)和对称计算函数(EVP_add_cipher)。

2.2 BIO扩充

包括bio_b64.c、bio_enc.c、bio_md.c和bio_ok.c,各自实现了BIO_METHOD方法,分别用于base64编解码、对称加解密以及摘要。

2.3 摘要算法EVP封装

由digest.c实现,实现过程中调用了对应摘要算法的回调函数。各个摘要算法提供了自己的EVP_MD静态结构,对应源码为m_xxx.c。

2.4 对称算法EVP封装

由evp_enc.c实现,实现过程调用了具体对称算法函数,实现了Update操作。各种对称算法都提供了一个EVP_CIPHER静态结构,对应源码为e_xxx.c。需要注意的是,e_xxx.c中不提供完整的加解密运算,它只提供基本的对于一个block_size数据的计算,完整的计算由evp_enc.c来实现。当用户想添加一个自己的对称算法时,可以参考e_xxx.c的实现方式。一般用户至少需要实现如下功能:

Ø 构造一个新的静态的EVP_CIPHER结构;

Ø 实现EVP_CIPHER结构中的init函数,该函数用于设置iv,设置加解密标记、以及根据外送密钥生成自己的内部密钥;

Ø 实现do_cipher函数,该函数仅对block_size字节的数据进行对称运算;

Ø 实现cleanup函数,该函数主要用于清除内存中的密钥信息。

2.5 非对称算法EVP封装

主要是以p_开头的文件。其中,p_enc.c封装了公钥加密;p_dec.c封装了私钥解密;p_lib.c实现一些辅助函数;p_sign.c封装了签名函数;p_verify.c封装了验签函数;p_seal.c封装了数字信封;p_open.c封装了解数字信封。

2.6 基于口令的加密

包括p5_crpt2.c、p5_crpt.c和evp_pbe.c。

三、开发实例

3.1 示例1

#include <string.h>#include <openssl/evp.h>int    main(){int                                ret,which=1;EVP_CIPHER_CTX             ctx;const EVP_CIPHER      *cipher;unsigned char        key[24],iv[8],in[100],out[108],de[100];int                                i,len,inl,outl,total=0;for(i=0;i<24;i++){memset(&key[i],i,1);}for(i=0;i<8;i++){memset(&iv[i],i,1);}for(i=0;i<100;i++){memset(&in[i],i,1);}EVP_CIPHER_CTX_init(&ctx);printf("please select :\n");printf("1: EVP_des_ede3_ofb\n");printf("2: EVP_des_ede3_cbc\n");scanf("%d",&which);if(which==1)cipher=EVP_des_ede3_ofb();elsecipher=EVP_des_ede3_cbc();ret=EVP_EncryptInit_ex(&ctx,cipher,NULL,key,iv);if(ret!=1){printf("EVP_EncryptInit_ex err1!\n");return -1;}inl=50;len=0;EVP_EncryptUpdate(&ctx,out+len,&outl,in,inl);len+=outl;EVP_EncryptUpdate(&ctx,out+len,&outl,in+50,inl);len+=outl;EVP_EncryptFinal_ex(&ctx,out+len,&outl);len+=outl;printf("加密结果长度:%d\n",len);/* 解密 */EVP_CIPHER_CTX_cleanup(&ctx);EVP_CIPHER_CTX_init(&ctx);ret=EVP_DecryptInit_ex(&ctx,cipher,NULL,key,iv);if(ret!=1){printf("EVP_DecryptInit_ex err1!\n");return -1;}total=0;EVP_DecryptUpdate(&ctx,de+total,&outl,out,44);total+=outl;EVP_DecryptUpdate(&ctx,de+total,&outl,out+44,len-44);total+=outl;ret=EVP_DecryptFinal_ex(&ctx,de+total,&outl);total+=outl;if(ret!=1){EVP_CIPHER_CTX_cleanup(&ctx);printf("EVP_DecryptFinal_ex err\n");return -1;}if((total!=100) || (memcmp(de,in,100))){printf("err!\n");return -1;}EVP_CIPHER_CTX_cleanup(&ctx);printf("test ok!\n");return 0;}

输出结果如下:

please select :1: EVP_des_ede3_ofb2: EVP_des_ede3_cbc1加密结果长度:100test ok!please select :1: EVP_des_ede3_ofb2: EVP_des_ede3_cbc2加密结果长度:104test ok!

3.2 示例2

#include <string.h>#include <openssl/evp.h>int    main(){int                                cnid,ret,i,msize,mtype;int                                mpktype,cbsize,mnid,mbsize;const EVP_CIPHER      *type;const EVP_MD             *md;int                                datal,count,keyl,ivl;unsigned char        salt[20],data[100],*key,*iv;const      char        *cname,*mname;type=EVP_des_ecb();cnid=EVP_CIPHER_nid(type);cname=EVP_CIPHER_name(type);cbsize=EVP_CIPHER_block_size(type);printf("encrypto nid : %d\n",cnid);printf("encrypto name: %s\n",cname);printf("encrypto bock size : %d\n",cbsize);md=EVP_md5();mtype=EVP_MD_type(md);mnid=EVP_MD_nid(md);mname=EVP_MD_name(md);mpktype=EVP_MD_pkey_type(md);msize=EVP_MD_size(md);mbsize=EVP_MD_block_size(md);printf("md info : \n");printf("md type  : %d\n",mtype);printf("md nid  : %d\n",mnid);printf("md name : %s\n",mname);printf("md pkey type : %d\n",mpktype);printf("md size : %d\n",msize);printf("md block size : %d\n",mbsize);keyl=EVP_CIPHER_key_length(type);key=(unsigned char *)malloc(keyl);ivl=EVP_CIPHER_iv_length(type);iv=(unsigned char *)malloc(ivl);for(i=0;i<100;i++)memset(&data[i],i,1);for(i=0;i<20;i++)memset(&salt[i],i,1);datal=100;count=2;ret=EVP_BytesToKey(type,md,salt,data,datal,count,key,iv);printf("generate key value: \n");for(i=0;i<keyl;i++)printf("%x ",*(key+i));printf("\n");printf("generate iv value: \n");for(i=0;i<ivl;i++)printf("%x ",*(iv+i));printf("\n");return 0;}

EVP_BytesToKey函数通过salt以及data数据来生成所需要的key和iv。

输出:

encrypto nid : 29encrypto name: DES-ECBencrypto bock size : 8md info :md type  : 4md nid  : 4md name : MD5md pkey type : 8md size : 16md block size : 64generate key value:54 0 b1 24 18 42 8d ddgenerate iv value:ba 7d c3 97 a0 c9 e0 70

3.3 示例3

#include <openssl/evp.h>#include <openssl/rsa.h>int    main(){int                         ret,inlen,outlen=0;unsigned long  e=RSA_3;char               data[100],out[500];EVP_MD_CTX             md_ctx,md_ctx2;EVP_PKEY            *pkey;RSA                      *rkey;BIGNUM               *bne;/* 待签名数据*/strcpy(data,"openssl 编程作者:赵春平");inlen=strlen(data);/* 生成RSA密钥*/bne=BN_new();ret=BN_set_word(bne,e);rkey=RSA_new();ret=RSA_generate_key_ex(rkey,1024,bne,NULL);if(ret!=1)  goto err;pkey=EVP_PKEY_new();EVP_PKEY_assign_RSA(pkey,rkey);/* 初始化*/EVP_MD_CTX_init(&md_ctx);ret=EVP_SignInit_ex(&md_ctx,EVP_md5(), NULL);if(ret!=1)goto err;ret=EVP_SignUpdate(&md_ctx,data,inlen);if(ret!=1)goto err;ret=EVP_SignFinal(&md_ctx,out,&outlen,pkey);/* 验证签名*/EVP_MD_CTX_init(&md_ctx2);ret=EVP_VerifyInit_ex(&md_ctx2,EVP_md5(), NULL);if(ret!=1) goto err;ret=EVP_VerifyUpdate(&md_ctx2,data,inlen);if(ret!=1) goto err;ret=EVP_VerifyFinal(&md_ctx2,out,outlen,pkey);if(ret==1)printf("验证成功\n");elseprintf("验证错误\n");err:RSA_free(rkey);BN_free(bne);return 0;}

3.4 示例4

#include <openssl/evp.h>#include <openssl/rsa.h>int    main(){int                         ret,ekl[2],npubk,inl,outl,total=0,total2=0;unsigned long  e=RSA_3;char               *ek[2],iv[8],in[100],out[500],de[500];EVP_CIPHER_CTX      ctx,ctx2;EVP_CIPHER        *type;EVP_PKEY            *pubkey[2];RSA                      *rkey;BIGNUM               *bne;/* 生成RSA密钥*/bne=BN_new();ret=BN_set_word(bne,e);rkey=RSA_new();ret=RSA_generate_key_ex(rkey,1024,bne,NULL);pubkey[0]=EVP_PKEY_new();EVP_PKEY_assign_RSA(pubkey[0],rkey);type=EVP_des_cbc();npubk=1;EVP_CIPHER_CTX_init(&ctx);ek[0]=malloc(500);ek[1]=malloc(500);ret=EVP_SealInit(&ctx,type,ek,ekl,iv,pubkey,1);  /* 只有一个公钥*/if(ret!=1) goto err;strcpy(in,"openssl 编程");inl=strlen(in);ret=EVP_SealUpdate(&ctx,out,&outl,in,inl);if(ret!=1)goto err;total+=outl;ret=EVP_SealFinal(&ctx,out+outl,&outl);if(ret!=1) goto err;total+=outl;memset(de,0,500);EVP_CIPHER_CTX_init(&ctx2);ret=EVP_OpenInit(&ctx2,EVP_des_cbc(),ek[0],ekl[0],iv,pubkey[0]);if(ret!=1) goto err;ret=EVP_OpenUpdate(&ctx2,de,&outl,out,total);total2+=outl;ret=EVP_OpenFinal(&ctx2,de+outl,&outl);total2+=outl;de[total2]=0;printf("%s\n",de);err:free(ek[0]);free(ek[1]);EVP_PKEY_free(pubkey[0]);BN_free(bne);getchar();return 0;}

输出结果:openssl 编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

揭秘Git高手的10个秘密武器:让你的工作效率飙升!

Git和GitHub是每个软件工程师都必须了解的最基本的工具。它们是开发人员日常工作不可或缺的一部分&#xff0c;每天都要与之互动。 精通Git不仅能简化你的日常操作&#xff0c;还能显著提高生产力。在这篇文章中&#xff0c;我们将探讨一组能够极大提升生产力的命令。 随着对…

适用于 Windows 的最佳电脑数据恢复软件是什么?

数据丢失是数字世界中令人不快的一部分&#xff0c;它会在某一时刻影响许多计算机用户。很容易意外删除一些重要文件&#xff0c;这可能会在您努力恢复它们时带来不必要的压力。幸运的是&#xff0c;数据恢复软件可以帮助恢复已删除的文件&#xff0c;即使您没有备份它们。这是…

智慧公厕为高速服务区公厕做出的贡献

在现代社会&#xff0c;科技的飞速发展改变了人们的生活方式&#xff0c;也深刻影响着城市的基础设施和公共服务。而在这个数字化时代的背景下&#xff0c;智慧公厕作为城市智能化管理的一部分&#xff0c;为高速服务区公厕带来了一系列的创新和贡献&#xff0c;为旅客的出行提…

动态规划经典例题leetcode思路代码详解

目录 动态规划基础篇例题 leetcode70题.爬楼梯 leetcode746题.使用最小花费爬楼梯 leetcode198题.打家劫舍 leetcode62题.不同路径 leetcode64题.最小路径和 leetcode63题.63不同路径II 动态规划基础篇例题 这一篇的例题解答是严格按照我上一篇写的动态规划三部曲做的&…

AI 发展的三次危机

前几天闹得沸沸扬扬的OpenAI宫斗事件终于落下帷幕&#xff0c;事情以奥特曼回归OpenAI继续担当CEO并且重组董事会结局。 看起来还算一个不错的结果。 OpenAI 作为目前全球大模型的领先者和佼佼者&#xff0c;他的一举一动肯定会影响整个人类 AI 的发展历程&#xff0c;这次宫…

P9242 [蓝桥杯 2023 省 B] 接龙数列(dp+最长接龙序列+分类)

1. 计算0~9为结尾的最长子串长度 2. 对于每个数字&#xff0c;比较其开头可连接子串长度1 与 原来以其末位为末尾的子串长度 3. 更新以其末位为末尾的子串长度 #include<iostream> #include<string.h>using namespace std;// 相当于记录…

万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞 附POC

@[toc] 万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文…

未来的大模型发展又会走向哪一边

近期&#xff0c;特斯拉CEO马斯克公开表示&#xff1a;OpenAI不该闭源&#xff0c;自家首款聊天机器人将开源。在数字化时代&#xff0c;开源与闭源软件的辩论一直是技术界的热门话题。开源是否能够带来更好的创新与合作&#xff1f;闭源是否能够保护商业利益与技术安全&#x…

力扣141-环形链表

文章目录 力扣141-环形链表示例代码实现要点剖析 力扣141-环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测…

重新认识电声器件!

电声器件&#xff1a;实现电声转换的重要工具 在科技快速发展的今天&#xff0c;电声器件已经深入到我们生活的方方面面。无论是音乐、语音通信、电影等娱乐领域&#xff0c;还是雷达、电子侦察等军事领域&#xff0c;甚至在生物医学工程中&#xff0c;如助听器和人工耳蜗等设备…

计算机基础知识60

MySQL分组 # 概念&#xff1a;分组是按照某个指定的条件将单个单个的个体分成一个个整体 # MySQL分组的关键字&#xff1a;group by # 分组一般配合聚合函数使用&#xff1a; sum max min avg count 基本的语法格式: group by 字段名 [having 条件表达式] # 单独使用 group by关…

再探Java集合系列—ArrayList

适用于什么场景&#xff1f; 检索比较多的场景&#xff0c;例如学生成绩管理系统&#xff0c;老师对学生的成绩进行排名或查询操作 ArrayList有哪些特点&#xff1f; 1、ArrayList集合底层采用了数组数据结构&#xff0c;是Object类型 2、动态数组。ArrayList的默认初始容量…

Makefile之 CFLAGS CXXFLAGS CC LDFLAGS LD

Makefile之 CFLAGS CXXFLAGS CC LDFLAGS LD 1&#xff09;CFLAGS&#xff1a;该环境变量用于指定C语言的编译器选项。它包含了编译C源代码时所需的选项&#xff0c;例如优化级别、警告级别、编译器标志等。在Makefile中&#xff0c;可以将CFLAGS设置为任何所需的编译器选项。例…

BSD socket API

API函数 以下函数是最基本的 socket API socket() 创造某种类型的套接字&#xff0c;分配一些系统资源&#xff0c;用返回的整数识别。 bind() 一般是用在服务器这边&#xff0c;和一个套接字地址结构相连&#xff0c;比如说是一个特定的本地端口号和一个IP地址。 listen()用在…

第1章 理解知识图谱(一)

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

SpringBoot : ch11 整合RabbitMQ

前言 在当今的互联网时代&#xff0c;消息队列成为了构建高可靠、高性能系统的重要组件之一。RabbitMQ作为一个可靠、灵活的消息中间件&#xff0c;被广泛应用于各种分布式系统中。 本篇博客将介绍如何使用Spring Boot整合RabbitMQ&#xff0c;实现消息的发送和接收。通过这种…

基于SpringBoot的教师工作量管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的教师工作量管理系统,ja…

硬件工程师助理怎么买器件

1. 买器件的要求。 1. 保证器件的质量。 2. 货期近可能的合适。 3.稳定渠道。 2. 器件到哪里买 1. 首先到立创商城去买&#xff0c;因为方便&#xff0c;价格明显&#xff0c;质量有保证。 立创商城链接&#xff1a;新人注册享元器件优惠券_新人特价商品_立创商城 (szlcsc.com…

视频集中存储/磁盘阵列EasyCVR平台黑名单异常解决步骤是什么?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

华为云(HECS)docker环境下安装jenkins

Jenkins是一个开源的自动化工具&#xff0c;可以自动化地完成构建、测试、交付或部署等任务。总之重点就是三个字&#xff1a;自动化&#xff0c;至于如何实现这些功能&#xff0c;Jenkins基于插件化的机制&#xff0c;提供了众多的插件来完成持续集成CI与持续部署CD。 【持续…