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

相关推荐
漫步企鹅5 天前
【漏洞修复】Android 10 系统源码中的 glibc、curl、openssl、cups、zlib 更新到最新版本
android·glibc·openssl·curl·zlib·漏洞修复·cups
Winter_Sun灬11 天前
curl库+openssl库windows编译
c++·windows·openssl·curl
ScilogyHunter15 天前
使用 OpenSSL 构建安全的网络应用
安全·openssl
dreadp22 天前
使用 OpenSSL 和 Python 实现 AES-256-CBC 加密与解密(安全密钥管理)
python·安全·网络安全·密码学·openssl
初级代码游戏1 个月前
编写一个基于OpenSSL的SSL/TLS服务端(HTTPS)可运行的完整示例
网络协议·https·ssl·openssl·tls
李洛克071 个月前
openssl的aes128_ECB加密解密运算实例
开发语言·算法·网络安全·openssl·aes算法
TsuanS1 个月前
OpenSSL 基础使用流程
网络·openssl
码农诗人1 个月前
调用openssl实现加解密算法
算法·openssl·ecdh算法
handsomestWei2 个月前
openssl使用
服务器·后端·ssl·openssl
初级代码游戏2 个月前
openssl 生成证书 windows导入证书
网络·网络协议·ssl·openssl