openssl3.2 - exp - buf to bio

文章目录

openssl3.2 - exp - buf to bio

概述

不想让程序调用openssl API时, 有文件落地的动作.

如果程序有配置文件要用, 也是自己读文件到buffer, 然后转成BIO给openssl的相关有BIO入参的API用.

如果在程序中用数组定义了一些PEM内容的数组, 也可以将数组转成BIO来用.

从openssl测试代码中, 找到了BIO_new_mem_buf(), 可以做这个事情.

那么程序需要的文件输入, 都可以读入buffer, 转成BIO, 后续都用BIO来处理.

笔记

c 复制代码
/*!
* \file main.cpp
* \note buffer to bio
*/

#include "my_openSSL_lib.h"

#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
#include <assert.h>

#include <openssl/bio.h>

int test_bio_new_mem_buf(void);

int main(int argc, char** argv)
{
    test_bio_new_mem_buf();
	return 0;
}

int test_bio_new_mem_buf(void)
{
    int ok = 0;
    BIO* bio = NULL;
    BUF_MEM* bufmem = NULL;
    char data[16];
    int i_rc = 0;

    do {
        // BIO_free(bio); // openssl做了处理, 即使入参为NULL, 也不会报错

        // BIO_new_mem_buf是直接将入参的buffer指到内部指针上, 所以入参指针如果是自己new出来的, 就需要自己释放

        // 如果是文件输入, 可以自己读文件到buffer中, 然后就用BIO来操作.
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break; 
        }
        
		i_rc = BIO_get_mem_ptr(bio, &bufmem);
        if (i_rc <= 0)
        {
            break;
        }

        memset(data, 0, sizeof(data));
        if (5 != BIO_read(bio, data, 5)) 
        { 
            break; 
        }

        if (0 != strncmp(data, "Hello", 5))
        {
            break;
        }

        // b->flags & BIO_FLAGS_MEM_RDONLY
        // bio默认是只读的, 是写不进去的.
        i_rc = BIO_write(bio, "test", 4);
        assert(i_rc <= 0);

        memset(data, 0, sizeof(data));
        i_rc = BIO_read(bio, data, 16); // 连续调用BIO_read时, 是继续往后读, 读一点, 内容就少一点
        assert(7 == i_rc); // 返回值是读了多少个字节

        if (0 != strncmp(data, " World\n", 7))
        {
            break;
        }

        i_rc = BIO_reset(bio); // 只读的bio可以恢复到刚创建时的状态, 可以从头开始读.
        assert(i_rc > 0);

        i_rc = BIO_read(bio, data, 16);
        assert(12 == i_rc);

        if (0 != strncmp(data, "Hello World\n", 12))
        {
            break;
        }

        ok = 1;
    } while (false);

    if (NULL != bio)
    {
        BIO_free_all(bio);
        bio = NULL;
    }
    
    return ok;
}

bio_get_length

openssl 并不提供如何得到BIO对象内容的size.

因为很多BIO是不知道有多长的(e.g. bio for ssl)

但是对于由buffer转成BIO之后, 其实BIO内的数据长度是确定的.

查了资料, 可以用 BIO_ctrl_pending()来取长度, 但是之前要先调用一下BIO_rest().

封装了一个函数bio_get_length(), 好使.

调用端代码

c 复制代码
        // 如果是文件输入, 可以自己读文件到buffer中, 然后就用BIO来操作.
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break; 
        }

        bio_length = bio_get_length(bio);
        assert(bio_length == 12);

函数实现

c 复制代码
size_t bio_get_length(BIO* bio)
{
	size_t bio_length = 0;

	do {
		if (NULL == bio)
		{
			break;
		}

		BIO_reset(bio);
		bio_length = BIO_ctrl_pending(bio);
	} while (false);

	return bio_length;
}

bio_to_buffer

如果想对一个已经包含了内容的BIO中的内容, 转为buffer. 以下代码好使.

c 复制代码
int test_bio_to_buffer(void)
{
    int ok = 0;
    BIO* bio = NULL;

    char data[16];
    int i_rc = 0;

    long bio_length = 0;
    uint8_t* pBufToLoadBIO = NULL;

    do {
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break;
        }

        // 得到BIO的数据长度, 才好去开buffer
        bio_length = bio_get_length(bio);
        assert(bio_length == 12);

        // 多开一个字节, 留一个'\0'的位置, 如果内容是可见字符, 看字符串方便
        pBufToLoadBIO = new uint8_t[bio_length + 1];
        if (NULL == pBufToLoadBIO)
        {
            break;
        }

        pBufToLoadBIO[bio_length] = '\0';

        i_rc = BIO_read(bio, pBufToLoadBIO, bio_length);
        // 如果 bio_length 太大(> imax), 再分段读来处理, 现在先这样, 就当一次就读完了
        assert(i_rc == bio_length);
        // 现在可以拿pBufToLoadBIO去干活了(自己存文件, 或作其他处理)

        ok = 1;
    } while (false);

    if (NULL != bio)
    {
        BIO_free_all(bio);
        bio = NULL;
    }

    if (NULL != pBufToLoadBIO)
    {
        delete []pBufToLoadBIO;
        pBufToLoadBIO = NULL;
    }

    return ok;
}

向一个mem BIO中任意写

c 复制代码
/*!
* \file main.cpp
*/

#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "CMemHookRec.h"

void my_openssl_app();
size_t bio_get_length(BIO* bio);

int main(int argc, char** argv)
{
	setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞
	mem_hook();

	my_openssl_app();

	mem_unhook();

	return 0;
}

void my_openssl_app()
{
	BIO* bio = NULL;
	int i_rc = 0;
	char szBuf[1024];
	size_t szWrited = 0;
	size_t sz_tmp = 0;
	int i = 0;

	do {
		bio = BIO_new(BIO_s_mem());
		if (NULL == bio)
		{
			break;
		}

		i_rc = BIO_test_flags(bio, BIO_FLAGS_MEM_RDONLY);
		assert(i_rc != BIO_FLAGS_MEM_RDONLY);

		for (i = 0; i < 10240; i++)
		{
			szBuf[0] = 't';
			i_rc = BIO_write_ex(bio, szBuf, sizeof(szBuf), &szWrited);
			assert((i_rc > 0) && (szWrited == sizeof(szBuf)));
			sz_tmp = bio_get_length(bio);
		}
	} while (false);

	if (NULL != bio)
	{
		BIO_free(bio);
		bio = NULL;
	}
}

size_t bio_get_length(BIO* bio)
{
	size_t bio_length = 0;

	// 只适合与已经全部装载了mem buffer内容的BIO
	// 因为 BIO_BUF_MEM 没有对外, 所以只能通过试读来确定BIO内容的长度
	do {
		if (NULL == bio)
		{
			break;
		}

		BIO_reset(bio);
		bio_length = BIO_ctrl_pending(bio);
	} while (false);

	return bio_length;
}

END

相关推荐
Lazy Dave12 天前
gmssl私钥文件格式
网络安全·ssl·openssl
沉在嵌入式的鱼1 个月前
RK3588移植Openssl库
linux·rk3588·openssl
黑屋里的马1 个月前
ssl相关命令生成证书
服务器·网络·ssl·openssl·gmssl
fangeqin2 个月前
ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
linux·python·ubuntu·openssl
API开发2 个月前
苹果芯片macOS安装版Homebrew(亲测) ,一键安装node、python、vscode等,比绿色软件还干净、无污染
vscode·python·docker·nodejs·openssl·brew·homebrew
码农不惑2 个月前
Rust使用tokio(二)HTTPS相关
https·rust·web·openssl
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法并通过OPENSSL加密验证算法正确性。
linux·服务器·c++·算法·安全·加密·openssl
liulilittle2 个月前
OpenSSL 的 AES-NI 支持机制
linux·运维·服务器·算法·加密·openssl·解密
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法。
linux·服务器·c++·算法·安全·加密·openssl
花花少年2 个月前
Ubuntu系统下交叉编译openssl
openssl·交叉编译