【OpenSSL】Base64 二进制数据编码解码(OpenSSL BIO)
1.问题引出
计算机中数据使用ascii码存储,而ascii码在128~255之间是不可见字符,网络上传输数据时往往经过多个路由设备,不同设备不同的处理方式也可能导致数据传输过程中处理出现问题。所以我们通过Base64将数据全部编码成可见字符(A-Z, a-z, 0-9, +, / 共64个)可以降低出错的可能。
- Base64应用:电子邮件的传输编码
- 附件中图片、音视频都是二进制的文件,但邮件传输协议只支持ASCII字符传递,所以普通的二进制文件传输无法实现
- HTTP协议要求请求行必须是ASCII编码
- 数据库读写 blob 中存储中文
- Base64算法
- 把一组3个字节转换成一组4个字节(编码后字符串变大了)
- 编码过程中如果最后一组3个字节凑不够,用0填充,输出字符使用'=',可能补充1个或2个'='来凑够3个字节一组

2. BIO
- BIO对象的创建
// 创建BIO对象
BIO *BIO_new(const BIO_METHOD *type);
// 封装了base64编码方法的BIO,写的时候进行编码,读的时候解码
BIO_METHOD* BIO_f_base64();
// 封装了内存操作的BIO接口,包括了对内存的读写操作
BIO_METHOD* BIO_s_mem(); // 创建一个内存型的BIO对象
// BIO * bio = BIO_new(BIO_s_mem());
BIO *BIO_new_mem_buf(void *buf, int len);
// 创建一个磁盘文件操作的BIO对象
BIO* BIO_new_file(const char* filename, const char* mode);
// 释放整个bio链
void BIO_free_all(BIO *a);
- BIO对象的读写操作
// 从BIO接口中读出len字节的数据到buf中。
// 成功就返回真正读出的数据的长度,失败返回0或-1,如果该BIO没有实现本函数则返回-2。
int BIO_read(BIO *b, void *buf, int len);
- buf: 存储数据的缓冲区地址
- len: buf的最大容量
// 往BIO中写入长度为len的数据。
// 成功返回真正写入的数据的长度,失败返回0或-1,如果该BIO没有实现本函数则返回-2。
int BIO_write(BIO *b, const void *buf, int len);
- buf: 要写入的数据, 写入到b对应的设备(内存/磁盘文件)中
- len: 要写入的数据的长度
// 将BIO内部缓冲区的数据都写出去, 成功: 1, 失败: 0或-1
int BIO_flush(BIO *b);
- 在使用BIO_write()进行写操作的时候, 数据有时候在openssl提供的缓存中
- 将openssl提供的缓存中的数据刷到设备(内存/磁盘文件)中
- BIO对象插入到链表中
// 把参数中名为append的BIO附加到名为b的BIO上,并返回b
// 连接两个bio对象到链表中
// 在链表中的关系: b->append
BIO * BIO_push(BIO *b, BIO *append);
- b: 要插入到链表中的头结点
- append: 头结点的后继
// 把名为b的BIO从一个BIO链中移除并返回下一个BIO,如果没有下一个BIO,那么就返回NULL。
BIO * BIO_pop(BIO *b);
- 通过定义BUF_MEM* ptr; 并使用 BIO_get_mem_ptr 函数来获取数据
typedef struct buf_mem_st BUF_MEM;
struct buf_mem_st {
size_t length; /* current number of bytes */
char *data;
size_t max; /* size of buffer */
unsigned long flags;
};
// 该函数也是一个宏定义函数,它将b底层的BUF_MEM结构放在指针pp中。
BUF_MEM* ptr;
long BIO_get_mem_ptr(BIO *b, BUF_MEM **pp);
- 一个BIO对象应用的例子,它可以很方便的完成一连串操作
BIO* md1 = BIO_new(xxx); // md1 hash计算
BIO* md2 = BIO_new(xxx); // md2 hash计算
BIO* b64 = BIO_new(xxx); // base64 编解码
BIO* f = BIO_new(xxx); // 操作磁盘文件 // 建立一个bio链
// b64->f
BIO_push(b64, f);// md2->b64->f
BIO_push(md2, b64);
// md1->md2->b64->f
BIO_push(md1, md2);
// 写数据操作 md1->md2->b64->f,读数据操作则相反
int BIO_write(md1, "hello, world", 11);
// 数据的处理过程 进行md1 的哈希计算 -> md2的哈希计算 -> base64编码 -> 数据被写到磁盘
2.1 Base64编解码
- base64编码
char* data = "hello, world";
// 创建base64编码的bio对象
BIO* b64 = BIO_new(BIO_f_base64());
// 最终在内存中得到一个base64编码之后的字符串
BIO* mem = BIO_new(BIO_s_mem());
// 将两个bio对象串联, 结构: b64->mem
BIO_push(b64, mem);
// 将要编码的数据写入到bio对象中,写数据应该传入头指针b64
BIO_write(b64, data, strlen(data)+1);
BIO_flush(BIO *b);
// 将数据从bio对象对应的内存中取出 -> char*
BUF_MEM* ptr;
// 数据通过ptr指针传出
long BIO_get_mem_ptr(b64, &ptr);
char* buf = new char[ptr->length];
memcpy(buf, ptr->data, ptr->length);
printf("编码之后的数据: %s\n", buf);
- base64解码
// 要解码的数据
char* data = "xxxxxxxxxxxxxxxxxxxx";
// 创建base64解码的bio对象
BIO* b64 = BIO_new(BIO_f_base64());
// 存储要解码的数据
BIO* mem = BIO_new(BIO_s_mem());
// 将数据写入到mem对应的内存中
BIO_write(mem, data, strlen(data));
// 上面两句也可以合成下面一句写BIO *mem = BIO_new_mem_buf(data, strlen(data)); // 组织bio链
BIO_push(b64, mem);
// 读数据(给头节点)因为是read,所以反向流动 b64 <- mem,最后输出到给定的buf中
char buf[1024];
int BIO_read(b64, buf, 1024);
printf("base64解码的数据: %s\n", buf);
【OpenSSL】Base64 二进制数据编码解码(OpenSSL BIO)的更多相关文章
- Openssl base64命令
一.简介 对文件件进行base64的编码与解码 二.语法 openssl base64 [-in filename] [-out filename] 三.实例 1.二进制文件与base64编码互转 o ...
- BASE64编码和解码(VC源代码) 并 内存加载 CImage 图像
BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本.完整的BASE64定义可见 RFC1421和 RFC2045.编码后的数据比原始数据略长,为原来的4/3.在电子 ...
- Android图片的Base64编码与解码
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法. Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较 ...
- Java 8中的Base64编码和解码
转自:https://juejin.im/post/5c99b2976fb9a070e76376cc Java 8会因为将lambdas,流,新的日期/时间模型和Nashorn JavaScript引 ...
- Base64编码与解码原理
Base64编码是使用64个可打印ASCII字符(A-Z.a-z.0-9.+./)将任意字节序列数据编码成ASCII字符串,另有“=”符号用作后缀用途. base64索引表 base64编码与解码的基 ...
- SSE图像算法优化系列三十一:Base64编码和解码算法的指令集优化。
一.基础原理 Base64是一种用64个Ascii字符来表示任意二进制数据的方法.主要用于将不可打印的字符转换成可打印字符,或者简单的说是将二进制数据编码成Ascii字符.Base64也是网络 ...
- base64编码、解码的C语言实现
转自:http://www.cnblogs.com/yejianfei/archive/2013/04/06/3002838.html base64是一种基于64个可打印字符来表示二进制数据的表示方法 ...
- Python中进行Base64编码和解码
Base64编码 广泛应用于MIME协议,作为电子邮件的传输编码,生成的编码可逆,后一两位可能有“=”,生成的编码都是ascii字符.优点:速度快,ascii字符,肉眼不可理解缺点:编码比较长,非常容 ...
- C#中Base64之编码,解码方法
原文:C#中Base64之编码,解码方法 1.base64 to string string strPath = "aHR0cDovLzIwMy44MS4yOS40Njo1NTU3L1 ...
- 使用window.btoa和window.atob来进行Base64编码和解码
方法描述 WindowBase64.atob() 函数用来解码一个已经被base-64编码过的数据. WindowBase64.btoa() 函数 将ascii字符串或二进制数据转换成一个base ...
随机推荐
- 将Spring Boot项目部署到自己的服务器上
第一步: 先准备好MobaXterm,链接上服务器后进入宝塔面板 https://www.bt.cn/new/download.html 找到Linux面板安装脚本复制命令 第二步: 进入MobaXt ...
- 晴神宝典之C /C++快速入门
OJ 补充:runtime error通常原因是数组越界,除零,异常调用,堆栈溢出 尽可能远离TLE 选择c++ 输入输出使用printf和scanf basis 变量名取名: (1)不能是c语言标识 ...
- 鸿蒙next 定位开发全场景实践
一.开场白 在智能设备普及的今天,位置服务已成为移动应用的基础设施.无论是外卖配送的实时轨迹追踪.导航应用的路径规划,还是运动健康类App的卡路里计算,精准的位置定位都是用户体验的关键支撑.鸿蒙nex ...
- 保姆教程系列:生成 SSH Key 并配置连接远程仓库
@ 目录 前言 第 1 步:检查是否已有 SSH Key 第 2 步:生成新的 SSH Key 第 3 步:启动 SSH Agent 并添加密钥 第 4 步:复制 SSH 公钥 第 5 步:添加 SS ...
- docker-compose 启动容器
docker-compose 是什么 docker-compose 是一个用来把 docker 自动化的东西.有了 docker-compose 你可以把所有繁复的 docker 操作全都一条命令,自 ...
- 上线啦丨FlinkX1.12 Beta版正式在Github开源
万众期待的FlinkX1.12的Beta版今天正式在Github社区开源上线啦!这是FlinkX技术团队潜心打造的新版本的FlinkX,设计文档和使用文档已在社区中推送,大家可以随时下载查阅,喜欢的同 ...
- 谷歌新AI工具杀疯了?免费,但有点坑!Gemini CLI 抢先实测
刚刚谷歌发布了一个很有意思的新产品 Gemini CLI,直接把 AI 塞进了终端里. 据 官方介绍,这个工具能: 处理大型代码库(高达 100 万的 token 上下文) 有多模态能力:能从 PDF ...
- 4G网关8305LN远程监控西门子触摸屏SMART 700IE ZLAN8305LN应用
1.概述 ZLAN8305LN是一款专门为工业环境设计的RS485设备数据采集器/物联网网关,他通过4G的方式传输,结合卓岚特有的P2P技术,无需构建公网服务器也可以同样随时随地采集设备的数据,本次案 ...
- C/C++语法都会,但一动手就懵?这29个实战项目专门解决这个问题
哈喽,小伙伴们好!我是小康 前段时间发了一篇 C++项目推荐 的文章:60个 Linux C/C++ 实战小项目,挑战年薪30万+,收到了超乎预期的反响!好多读者朋友私信我说: "小康哥,这 ...
- vant封装城市/联系人等选择器
封装成组件 <template> <div class="common-ibar"> <van-search class="search&q ...