最近项目上需要对一段二进制串进行 base64编码、解码, base64编码、解码的算法并不复杂,自行实现也不会引入太大代价,不过既然openssl 有比较成熟的实现,直接调用库代码自然是比较明智的选择。

具体实践过程中,遭遇些细节问题,折腾许久,方才搞定,特此记下,便于以后查阅,同时shared给后来人:
openssl 中 base64编码相关的几个函数如下:
----------------- 转载自其它blog,正确性已经过验证 ------------------------------
编码函数:

Ø         EVP_EncodeInit函数

原型:void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);

功能:该函数初始化一个用来进行base64编码的结构,事实上,该函数只是简单设置了结构里面几个常量的长度。

参数:

ctx:base64设备上下文。

Ø         EVP_EncodeUpdate函数

原型:void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,unsigned char *in,int inl);

功能:该函数将参数in里面的inl自己数据拷贝到结构体ctx里面,如果结构体里面有数据,就同时将结构体里面的数据进行BASE64编码并输出到参数out指向的缓存里面,输出数据的长度保存在outl里面。注意,在第一次调用本函数的时候,虽然往结构体里面拷贝数据了,但是结构体ctx里面开始是没有输入数据存在并且输入数据长度不超出ctx内部存储数据的最长限制,就不会有任何数据被进行BASE64编码,也就是说,不会有任何数据输出;但是如果输入数据长度比内部存储的数据长,那么就会输出部分经过BASE64编码的数据。数据输出总是在下一层输入前完成的。

参数:

ctx:base64设备上下文。

out:存放编码后的数据缓冲区。

outl:编码后的数据长度。

in:编码前的数据。

inl:编码前的数据长度。

Ø         EVP_EncodeFinal函数

原型:void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl);

功能:该函数将结构体ctx里面剩余数据进行BASE64编码并写入到参数out里面去,输出数据的长度保存在outl里面。

参数:

ctx:base64设备上下文。

out:存放编码后的数据。

outl:编码后的数据长度。

Ø         EVP_EncodeBlock函数

原型:int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);

功能:该函数将参数f里面的字符串里面的n个字节的字符串进行BASE64编码并输出到参数t里面。返回数据的字节长度。事实上,在函数EVP_EncodeUpdate和EVP_EncodeFinal里面就调用了该函数完成BASE64编码功能。

参数:

t:接收编码后的数据缓冲区。

f:编码前的数据。

n:编码前的数据长度。

  解码函数:
        Ø       EVP_DecodeInit 函数

原型:void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);

功能:该函数初始化一个用来进行BASE64解码的数据结构。

参数:

ctx:base64设备上下文。

Ø         EVP_DecodeUpdate函数

原型:int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,unsigned char *in, int inl);

功能:该函数将参数in里面inl字节的数据拷贝到结构体ctx里面。如果结构体里面已经有数据,那么这些数据就会先进行BASE64解码,然后输出到参数out指向的内存中,输出的字节数保存在参数outl里面。输入数据为满行的数据时,返回为1;如果输入数据是最后一行数据的时候,返回0;返回-1则表明出错了。

参数:

ctx:base64设备上下文。

out:存放解码后的数据缓冲区。

outl:解码后的数据长度。

in:解码前的数据。

inl:解码前的数据长度。

Ø         EVP_DecodeFinal函数

原型:int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);

功能:该函数将结构体ctx里面剩余的数据进行BASE64解码并输出到参数out指向的内存中,输出数据长度为outl字节。成功返回1,否则返回-1。

参数:

ctx:base64设备上下文。

out:解码后的数据。

outl:解码后的数据长度。

Ø         EVP_DecodeBlock函数

原型:int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);

功能:该函数将字符串f中的n字节数据进行BASE64解码,并输出到t指向的内存中,输出数据长度为outl。成功返回解码的数据长度,返回返回-1。

参数:

t:接收解码后的数据缓冲区。

f:解码前的数据。

       n :解码前的数据长度。
   --------------------- 上述函数声明为转载内容 ---------------------------
这些函数声明对应声明在头文件 /usr/include/openssl/evp.h 中。(具体路径视安装情况可能略有差异)。
按照base64的算法,任何长度的串编码后长度均未4的倍数, 解码后均未3的倍数。
理论上,编码(encode)时,如果输入串不是3的倍数,会在后面补0,以保持3的倍数,反映到encode后的串,就是后面对应补了'=', '='在正常base64编码中不会存在,因此,base64解码时有能力去除尾部的'/0'(虽然上述有些函数没有这么干)。
问题1: 直接使用EVP_EncodeBlock(...) / EVP_DecodeBlock(...) 编码、解码,原串经过编码、解码后可能无法还原!---尾部可能会多'/0', 比如:
'1234'
--> EVP_EncodeBlock(...) 变为:'MTIzNA=='  
--> EVP_DecodeBlock(...) 变为:'1234/0/0' 尾部多了两个/0
当然这对于以/0结尾的字符串是没影响的,对于二进制数据则直接意味着错误!
为简便起见,我在程序中直接使用了EVP_EncodeBlock /EVP_DecodeBlock 编、解码, 这个问题困扰了很长时间,更无语的是,google、baidu 关于openssl base64编、解码的说明寥寥无几,仅有的相关博文也几乎仅限于api的说明,还被copy来copy去,很多函数原型都不对了!  相关函数的声明头文件中更是一行注释都没有(这个比较ft -,-|| )
最后在google下 用纯e文搜索才找出点端倪:(一下内容未查阅源码,为e文论坛上直接摘录、翻译)
EVP_DecodeBlock内部同样调用EVP_DecodeInit + EVP_DecodeUpdate + Evp_DecodeFinal实现,但是并未处理尾部的'='字符,因此结果字符串长度总是为3的倍数。若要获取精确的正确长度,外部需添加额外代码,类似下面这样:
while(input_str[--input_str_len] = '=') output_len--;
return output_len; // 获取实际长度
实际就是原输入串尾部有几个 '=', decode后输出串的长度减几久ok了。
问题2: 直接使用EVP_DecodeInit + EVP_DecodeUpdate + EVP_DecodeFinal 组合进行decode是可以处理尾部'='字符,正确获取原串长度的,不过code会看起来零碎很多,用起来感觉也不是很友好,贴个解码的示例code 如下,编码类同。(ms现在都baidu不到示例code的)
//!< encode test int src_str_size = 60; unsigned char *src_str = (unsigned char *)malloc(src_str_size); memset(src_str, '1', src_str_size); unsigned char *encode_str = (unsigned char *)malloc( (src_str_size - 1) / 3 * 4 + 4); int encode_str_size = EVP_EncodeBlock(encode_str, src_str, src_str_size); printf("encode_str_size=%d encode_str:'%s'/n", encode_str_size, encode_str); //!< decode test EVP_ENCODE_CTX ctx; EVP_DecodeInit(&ctx); unsigned char *decode_str = (unsigned char *)malloc(src_str_size); int decode_str_size = 0; int len = 20; //!< 每次decode 的字节数 int decode_len = 0; int offset = 0; while(1) { if(offset + len > encode_str_size) { len = encode_str_size - offset; } int ret = EVP_DecodeUpdate(&ctx, decode_str + decode_str_size, &decode_len, encode_str + offset, len); if(ret == 0) break; if(ret == -1) { printf("error.../n"); break; } offset += len; decode_str_size += decode_len; } EVP_DecodeFinal(&ctx, decode_str, &decode_len); decode_str_size += decode_len; printf("decode_str:'%s' decode_str_len=%d/n", decode_str, decode_str_size);    
其中EVP_DecodeUpdate 函数,尾部的len参数不可太长(ms最大65),否则会出错
----------------
openssl 库应用甚少,了解也是皮毛,欢迎大家指正。
----------------

openssl base64 编、解码相关推荐

  1. 通过OpenSSL的接口实现Base64编解码

    对openssl genrsa产生的rsa私钥pem文件,使用普通的base64解码会有问题,如使用https://blog.csdn.net/fengbingchun/article/details ...

  2. Java实现BASE64编解码

    Java实现BASE64编解码 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs BASE64和其它类似的编码算法通经常使用于转换二进制数据为文本数据,其目 ...

  3. python 图片base64 编解码,转换成Opencv,PIL.Image图片格式

    Python PIL.Image和OpenCV图像格式相互转换 二进制打开图片文件,base64编解码转成Opencv格式: # coding: utf-8 import base64 import ...

  4. Delphi 自带的 Base64 编解码函数

    今天帮别人解决一个关于 Base64 编解码的问题,竟然发现 Delphi 自带了 Base64 编解码的单元,叫 EncdDecd,这名字很拗口而且不直观,估计这是一直很少人关注和知道的原因. 这个 ...

  5. Java 8实现BASE64编解码

    Java 8实现BASE64编解码 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用 ...

  6. Notepad++插件Base64编解码

    我们平常进行Base64编码需要自己写代码转换, 或者使用其他人编写的小工具程序, 也可以使用在线base64编码工具, 现在我们还可以使用Notepad++自带的插件, 进行Base64编码和解码, ...

  7. Python学习教程:Python3内置模块之base64编解码方法小结

    Python学习教程:Python3内置模块之base64编解码方法小结 概述 Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64 就是一种基于 64 个可打印字符来 ...

  8. ubuntu下c++中base64编解码测试和图片编解码测试

    全栈工程师开发手册 (作者:栾鹏) 架构系列文章 字符数组的base64编解码 base64.h #include <string>std::string base64_encode(un ...

  9. MSDK手Q邀请透传参数问题:url编解码与base64编解码

    最近做MSDK手Q的邀请功能,遇到一个坑,手Q结构化消息分享功能接口如下: /*** @param scene 标识发送手Q会话或者Qzone* eQQScene.QQScene_QZone: 分享到 ...

最新文章

  1. python模块之image修改图片类型
  2. 2020牛客多校第1场H-Minimum-cost Flow
  3. Flask 数据迁移 报错 Table 'xxx' is already defined for this MetaData instance
  4. Java调用Oracle存储Package
  5. VS集成Qt开发入门(简易时间显示)
  6. 2021年青海省大学生首届网络安全知识与技能大赛——赛题回顾及基本讲解
  7. bzoj 1704: [Usaco2007 Mar]Face The Right Way 自动转身机
  8. php如何架构设计,PHP – 架构设计帮助 – OOP固体原则
  9. python面试专题--with 关键字与上下文管理
  10. 计算机考研政治考哪些知识,带你了解408考研大纲,及21考研政治复习建议
  11. 小米 OJ 编程比赛 02 月常规赛 (Carryon 数数字)
  12. 一个简单的条码/二维码扫描App
  13. excel多个窗口独立显示_收藏!Excel快捷键
  14. ffmpeg将amr文件转成mp3文件
  15. 未来全世界油气的发展之路
  16. 3月4日 与柳传志面对面(谁是这个时代的思想家)
  17. adb命令删除offline离线手机设备
  18. 登录页面渗透测试思路总结
  19. 计算机科学期刊是ISTP吗,ISTP期刊是核心期刊吗
  20. TabLayout修改文字间距

热门文章

  1. ipad分屏怎么用_如何装备一个学术型的 iPad?
  2. 使用ActiveMovie控件制作多媒体播放器(支持MP3,WAV,dat,wma,mpeg,avi等)
  3. java客户咨询问题_对客户进行需求分析时,你会问哪些问题?请列举八个。
  4. python入门--第一天
  5. python 使用 selenium 爬虫知乎
  6. 辽宁启迪:开店手把手细心教学版
  7. 开发小程序(一)设置四宫格
  8. Arduino IDE 控制 RGB_LED 全彩灯(ESP8266示例)
  9. Android开发之 Wifi扫描分析
  10. HTML5笔记+案例