openssl3.2 - exp - 内存操作(建立,写入,读取)配置
文章目录
- openssl3.2 - exp - 内存操作(建立,写入,读取)配置
- 概述
- 笔记
- 调试细节
- 运行效果
- 测试工程实现
- main.cpp
- CMyOsslConfig.h
- CMyOsslConfig.cpp
- END
openssl3.2 - exp - 内存操作(建立,写入,读取)配置
概述
我的应用的配置文件是落地加密的, 无法直接用openssl配置接口载入读取.
应用先将加密的配置文件解密(openssl官方给的demo工程中有对文件的加解密例子).
从明文buffer中载入配置, 然后就可以用openssl的配置接口(BIO为入参)读取配置项的值.
做了实验, 用了1天搞定了. 封装了一个配置类. 可以在内存中建立配置, 写入配置, 读取配置.
在内存中建立配置,写入配置在服务端用.
客户端只用在内存中读取配置的接口.
笔记
调试细节
- NCONF_load_bio()执行后, 会将输入的BIO内容清掉.
- BIO_read()执行后, 如果后续不是要继续读取, 需要将数据读指针位置复原 BIO_seek(bio, 0)
- 如无必要, 不要调用BIO_seek(). 查了openssl实现, 官方用法全部是BIO_seek(bio, 0).
- 官方配置操作接口, 只有读取的接口. 因为官方用法, 都是用户自己手工编辑配置文件, openssl只需要读配置. 如果需要写配置内容, 需要自己封装(write buffer => BIO => CONF). 如果想自己确认写入BIO的内容是否正确, 可以将BIO写到文件来确认.
运行效果
[cpt_info] win_ver = win10
[cpt_info] ram = 32GB
[cfg_info] sec_cnt = 2
free mem_hook map, g_mem_hook_map.size() = 0, no openssl API call memory leak
测试工程实现
main.cpp
/*!
* \file main.cpp
*/#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>#include <openssl/conf.h> // for CONF#include "CMyOsslConfig.h"#include <stdlib.h>
#include <stdio.h>
#include <assert.h>#include "CMemHookRec.h"void my_openssl_app();int main(int argc, char** argv)
{setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞mem_hook();my_openssl_app();mem_unhook();/*! run result[cpt_info] win_ver = win10[cpt_info] ram = 32GB[cfg_info] sec_cnt = 2free mem_hook map, g_mem_hook_map.size() = 0, no openssl API call memory leak*/return 0;
}void my_openssl_app()
{CONF* conf = NULL;STACK_OF(CONF_VALUE)* sk_of_conf_value = NULL;CONF_VALUE* conf_value = NULL;CMyOsslConfig _cfg;bool b_rc = false;const char* pszVal = NULL;do {// case - wirte new config to BIO/CONFb_rc = _cfg.init(); // !!assert(b_rc);_cfg.add_config_section("cpt_info");_cfg.add_config_item_after_section("win_ver", "win10");_cfg.add_config_item_after_section("ram", "32GB");_cfg.add_config_section("cfg_info");_cfg.add_config_item_after_section("sec_cnt", "2");// 如果要将_cfg中的BIO中的东西写入文件测试(方便人工观察配置文件是否写错?), 必须要在_cfg.updateConfig()之前, 否则BIO中的东西被NCONF_load_bio()载入后清掉了// _cfg.to_file("test.cfg"); // only for test// when add config content, need update(bio to CONF)_cfg.updateConfig(); // !!// 经过_cfg.updateConfig()后, _cfg中的BIO就空了, 如果要更新配置, 就需要重新写BIO// get cofig value from CONF* inside on CMyOsslConfigpszVal = _cfg.get_conf_item_value("cpt_info", "win_ver");if (NULL != pszVal){printf("[cpt_info] win_ver = %s\n", pszVal);}pszVal = _cfg.get_conf_item_value("cpt_info", "ram");if (NULL != pszVal){printf("[cpt_info] ram = %s\n", pszVal);}pszVal = _cfg.get_conf_item_value("cfg_info", "sec_cnt");if (NULL != pszVal){printf("[cfg_info] sec_cnt = %s\n", pszVal);}} while (false);
}
CMyOsslConfig.h
//! \file CMyOsslConfig.h#ifndef __CMYOSSLCONFIG_H__
#define __CMYOSSLCONFIG_H__#include <openssl/bio.h>
#include <openssl/conf.h> // for CONFclass CMyOsslConfig
{
public:CMyOsslConfig();virtual ~CMyOsslConfig();bool init();bool add_config_section(const char* pszIn);bool add_config_item_after_section(const char* pszItemName, const char* pszItemContent);bool updateConfig();BIO* get_bio();char* get_conf_item_value(const char* group, const char* name);bool to_file(const char* psz_file_pathname); // for test onlyprivate:bool append_to_bio(uint8_t* pBuf, int lenBuf);size_t bio_get_length(BIO* bio);bool bio_to_buf(BIO* bio, uint8_t*& pBuf, int& lenBuf);private:BIO* m_bio;CONF* m_conf;
};#endif // #ifndef __CMYOSSLCONFIG_H__
CMyOsslConfig.cpp
//! \file CMyOsslConfig.cpp#include "CMyOsslConfig.h"
#include <string.h>
#include <openssl/err.h>
#include <cassert>CMyOsslConfig::CMyOsslConfig():m_bio(NULL),m_conf(NULL)
{}CMyOsslConfig::~CMyOsslConfig()
{if (NULL != m_bio){BIO_free(m_bio);m_bio = NULL;}if (NULL != m_conf){NCONF_free(m_conf);m_conf = NULL;}
}bool CMyOsslConfig::init()
{bool b_rc = false;do {if (NULL == m_bio){m_bio = BIO_new(BIO_s_mem());if (NULL == m_bio){break;}}if (NULL == m_conf){m_conf = NCONF_new_ex(OSSL_LIB_CTX_get0_global_default(), NULL);if (NULL == m_conf){break;}}b_rc = true;} while (false);return b_rc;
}bool CMyOsslConfig::add_config_section(const char* pszIn)
{bool b_rc = false;char szBuf[1024];int len = 0;do {if (NULL == pszIn){break;}len = strlen(pszIn);if (len > (sizeof(szBuf) - 0x10)){break;}sprintf(szBuf, "[ %s ]\n", pszIn);if (NULL == m_bio){break;}if (!append_to_bio((uint8_t*)szBuf, strlen(szBuf))){break;}b_rc = true;} while (false);return b_rc;
}bool CMyOsslConfig::add_config_item_after_section(const char* pszItemName, const char* pszItemContent)
{bool b_rc = false;char szBuf[1024];int len = 0;do {if ((NULL == pszItemName) || (NULL == pszItemContent)){break;}len = (strlen(pszItemName) + strlen(pszItemContent));if (len > (sizeof(szBuf) - 0x10)){break;}sprintf(szBuf, "%s = %s\n", pszItemName, pszItemContent);if (NULL == m_bio){break;}if (!append_to_bio((uint8_t*)szBuf, strlen(szBuf))){break;}b_rc = true;} while (false);return b_rc;
}bool CMyOsslConfig::append_to_bio(uint8_t* pBuf, int lenBuf)
{bool b_rc = false;int len = 0;size_t szLen = 0;int bio_len_before = 0;int bio_len_after = 0;do {if ((NULL == pBuf) || (lenBuf <= 0)){break;}if (NULL == m_bio){break;}// szLen = bio_get_length(m_bio);// BIO_seek(m_bio, szLen);bio_len_before = bio_get_length(m_bio);len = BIO_write(m_bio, pBuf, lenBuf);bio_len_after = bio_get_length(m_bio);if (len != lenBuf){break;}if (len != (bio_len_after - bio_len_before)){break;}b_rc = true;} while (false);return b_rc;}BIO* CMyOsslConfig::get_bio()
{if (NULL != m_bio){// BIO_seek(m_bio, 0);}return m_bio;
}size_t CMyOsslConfig::bio_get_length(BIO* bio)
{size_t bio_length = 0;do {if (NULL == bio){break;}// BIO_seek(bio, 0);bio_length = BIO_ctrl_pending(bio);} while (false);return bio_length;
}bool CMyOsslConfig::updateConfig()
{bool b_rc = false;int i_rc = 0;long lineSn = 0;int len1 = 0;int len2 = 0;do {if ((NULL == m_bio) || (NULL == m_conf)){break;}// BIO_seek(m_bio, 0);// len1 = this->bio_get_length(m_bio);i_rc = NCONF_load_bio(m_conf, m_bio, &lineSn);// len2 = this->bio_get_length(m_bio);// m_bio有东西有数据长度, 但是经过NCONF_load_bio()后, m_conf里面有东西了, 但是m_bio的东西没了// 所以, 经过NCONF_load_bio后(), 就得当m_bio是空的来处理.// 如果是向m_bio中写东西, 然后写配置.// 如果要更新m_bio中的配置内容, 就必须重新写.if (i_rc <= 0){break;}b_rc = true;} while (false);return b_rc;
}char* CMyOsslConfig::get_conf_item_value(const char* group, const char* name)
{char* res = NULL;int i_rc = 0;do {if (NULL == m_conf){break;}res = NCONF_get_string(m_conf, group, name);if (NULL == res){ERR_pop_to_mark();}else {ERR_clear_last_mark();}} while (false);return res;
}bool CMyOsslConfig::to_file(const char* psz_file_pathname)
{bool b_rc = false;FILE* pf = NULL;uint8_t* pBuf = NULL;int len = 0;size_t sz_rc = 0;do {if (NULL == psz_file_pathname){break;}pf = fopen(psz_file_pathname, "wb");if (NULL == pf){break;}if (!bio_to_buf(get_bio(), pBuf, len)){break;}if ((NULL == pBuf) || (len <= 0)){break;}sz_rc = fwrite(pBuf, sizeof(char), len, pf);assert(sz_rc == len);b_rc = true;} while (false);if (NULL != pf){fclose(pf);pf = NULL;}if (NULL != pBuf){OPENSSL_free(pBuf);pBuf = NULL;}return b_rc;
}bool CMyOsslConfig::bio_to_buf(BIO* bio, uint8_t*& pBuf, int& lenBuf)
{bool b_rc = false;int i_rc = 0;do {if (NULL == bio){break;}lenBuf = bio_get_length(bio);pBuf = (uint8_t*)OPENSSL_malloc(lenBuf + 1);if (NULL == pBuf){break;}pBuf[lenBuf] = '\0';i_rc = BIO_read(bio, pBuf, lenBuf);BIO_seek(bio, 0); // ! 读完了, 将数据读指针恢复.b_rc = (i_rc == lenBuf);} while (false);return b_rc;
}
END
相关文章:
openssl3.2 - exp - 内存操作(建立,写入,读取)配置
文章目录 openssl3.2 - exp - 内存操作(建立,写入,读取)配置概述笔记调试细节运行效果测试工程实现main.cppCMyOsslConfig.hCMyOsslConfig.cppEND openssl3.2 - exp - 内存操作(建立,写入,读取)配置 概述 我的应用的配置文件是落地加密的, 无法直接用openssl配置接口载入读取…...
前端食堂技术周刊第 114 期:Interop 2024、TS 5.4 RC、2 月登陆浏览器的新功能、JSR、AI SDK 3.0
美味值:🌟🌟🌟🌟🌟 口味:凉拌鸡架 食堂技术周刊仓库地址:https://github.com/Geekhyt/weekly 大家好,我是童欧巴。欢迎来到前端食堂技术周刊,我们先来看下…...
#QT(信号与槽)
1.IDE:QTCreator 2.实验:自动添加槽函数,手动添加槽函数 3.记录 (1)自动添加 a.拖拽widget.ui,放置push-button组件,并且自动生成槽函数 b.发现widget.cpp和widget.h中出现添加的槽函数,注意w…...
go 设置滚动日志
方案 通过 log/slog 实现结构化日志生成,这是go1.21中推出的新特性;通过 lumberjack 实现日志文件分割。 示例 package mainimport ("gopkg.in/natefinch/lumberjack.v2""log/slog""os""path/filepath" )fun…...
Rollup入门学习:前端开发的构建利器
在前端开发领域,构建工具对于优化项目结构和提升代码效率扮演着至关重要的角色。Rollup作为一款轻量级且功能强大的JavaScript模块打包器,近年来备受开发者青睐。本文将带你走进Rollup的世界,帮助你快速入门并掌握其核心用法。 一、Rollup简介…...
游戏寻路之A*算法(GUI演示)
一、A*算法介绍 A*算法是一种路径搜索算法,用于在图形网络中找到最短路径。它结合了Dijkstra算法和启发式搜索的思想,通过综合利用已知的最短路径和估计的最短路径来优化搜索过程。在游戏自动寻路得到广泛应用。 二、A*算法的基本思想 在图形网络中选择一个起点和终点。维护…...
软件工程顶会——ICSE '24 论文清单、摘要
1、A Comprehensive Study of Learning-based Android Malware Detectors under Challenging Environments 近年来,学习型Android恶意软件检测器不断增多。这些检测器可以分为三种类型:基于字符串、基于图像和基于图形。它们大多在理想情况下取得了良好的…...
Vue点击复制到剪切板
一、Vue2写法 安装 (官网地址) npm install --save vue-clipboard2 使用 //main.js import VueClipboard from vue-clipboard2 Vue.use(VueClipboard)//页面使用 <button type"button"v-clipboard:copy"message"v-clipboard:su…...
链路负载均衡之DNS透明代理
一、DNS透明代理 一般来说,企业的客户端上都只能配置一个运营商的DNS服务器地址,DNS服务器通常会将域名解析成自己所在ISP内的Web服务器地址,这将导致内网用户的上网流量都集中在一个ISP的链路上转发,最终可能会造成链路拥塞&…...
2024大语言模型LLM基础|语义搜索Semantic_Search全解
目录 语义搜索Semantic_Search代码详解 为甚麽用Pinecone做向量索引?优点是什么? 有哪些常见向量索引方法? Pinecone做向量索引怎么用? 向量索引全解:含原理解析: 语义搜索Semantic_Search代码详解 1…...
vue中使用echarts实现人体动态图
最近一直处于开发大屏的项目,在开发中遇到了一个小知识点,在大屏中如何实现人体动态图。然后看了下echarts官方文档,根据文档中的示例调整出来自己想要的效果。 根据文档上发现 series 中 type 类型设置为 象形柱形图,象形柱图是…...
结构化思维助力Prompt创作:专业化技术讲解和实践案例
结构化思维助力Prompt创作:专业化技术讲解和实践案例 最早接触 Prompt engineering 时, 学到的 Prompt 技巧都是: 你是一个 XX 角色… 你是一个有着 X 年经验的 XX 角色… 你会 XX, 不要 YY.. 对于你不会的东西, 不要瞎说!…对比什么技巧都不用, 直接像使用搜索引…...
【0272】postgres内核分配 MyBackendId 实现原理(MyBackendId、MyProc、shmInvalBuffer)(三)
相关文章: 【0255】揭晓pg内核中MyBackendId的分配机制(后端进程Id,BackendId)(一) 【0256】揭晓pg内核中MyBackendId的分配机制(后端进程Id,BackendId)(二) 第一个backend process前,shmInvalBuffer的值情况 (gdb) p *shmInvalBuffer $153 = {minMsgNum =...
AUKFUKF的MATLAB程序,含源码
adaptive UKF与UKF效果对比 只有一个m文件,直接拖到MATLAB上面就能运行并输出结果了 部分结果 程序源码 % adaptive UKF与UKF效果对比 % author:Evand % 作者联系方式:evandjiang@qq.com(除前期达成一致外,付费咨询) % date: 2023-11-07 % Ver1 clear;clc;close all; %%…...
STM32(13)串口
串口的数据帧 1.空闲 2.起始位 3.数据位 4.校验位(可有可无) 为了验证数据传输是否出错而设立的比特位 1和4传输方式比较常见 校验规则: 根据1的个数,校验位会自己补0或1 5.停止位 例子: 同步通信 异步通信 波特率 …...
Element(Java后端入门篇)
Element(Java后端入门篇) Element:是饿了么公司前端开发团队提供的一套基于Vue的网站组件库,用于快速构建网页组件:组成网页的部件,例如超链接、按钮、图片、表格等等~ Element快速入门 引入Element的css、js文件和V…...
qt5和gstreamer开发环境安装配置
构建KDE虚拟机环境 1、安装virtualBox 2、导入镜像 配置QtCreator开发环境 https://blog.csdn.net/weixin_45824067/article/details/131970558(安装的是qt6) https://blog.csdn.net/m0_70849943/article/details/132472950 (安装的qt版本为5.14.2&…...
基于Python3的数据结构与算法 - 10 计数排序
一、问题 对列表进行排序,已知列表中的数范围都在0到100之间。设计时间复杂度为O(n)的算法。 二、解决思路 我们已知数字的范围,那么我们可以将数字的个数得到: 例如:有一个0~5的列表 [1,3,2,4,1,2,3,1,3,5] 则共有0个0&am…...
力扣206反转链表
206.反转链表 力扣题目链接(opens new window) 题意:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 1,双指针 2,递归。递归参考双指针更容易写, 为什么不用头插…...
【python实战】--图片创作视频
系列文章目录 文章目录 系列文章目录前言一、VideoWriter_fourcc()常见的编码参数二、使用步骤1.引入库 总结 前言 一、VideoWriter_fourcc()常见的编码参数 cv2.VideoWriter_fourcc(‘M’, ‘P’, ‘4’, ‘V’)MPEG-4编码 .mp4 可指定结果视频的大小cv2.VideoWriter_fourcc…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
