OpenSSL之BASE64用法

BASE64编码的由来:
因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送。这样用途就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了。最好的方法就是在不改变传统协议的情 况下,做一种扩展方案来支持二进制文件的传送。把不可打印的字符也能用可打印字符来表示,问题就解决了。BASE64编码应运而生,BASE64就是一种基于64个可打印字符来表示二进制数据的表示方法。

本文假设你已经安装好了OpenSSL,并且持有一份1.1.1的源码。
BASE64相关的头文件在evp.h中、源文件在crypto/evp目录中,主要为encode.c。

主要结构:

struct evp_Encode_Ctx_st {
    int num;
    int length;
    unsigned char enc_data[80];
    int line_num;
    unsigned int flags;
};
typedef struct evp_Encode_Ctx_st EVP_ENCODE_CTX;

这个结构定义了BASE64编解码内部的缓冲信息。主要字段含义:
num—— 当前缓冲的未编码的块大小。
length —— 定义内部进行编解码计算的块大小,如编码时设定为48,解码时设定为64。
enc_data —— 内部编解码缓冲区。
line_num —— 行号,未使用。
flags—— 相关标志,如EVP_ENCODE_CTX_NO_NEWLINES表示编码时执行分行处理。

在1.1.1中,大多数的数据结构已经不再向使用者开放,从封装的角度来看,这是更合理的。如果你在头文件中找不到结构定义,不妨去源码中搜一搜。

主要函数:

EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void);
创建编解码上下文对象,编码和解码的上下文对象是一样的。
void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx);
释放编解码上下文对象。

void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
初使化编码上下文。
int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl);
对一段内存执行编码,输出编码数据。
成功返回1,失败返回0。
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
接收余下的编码数据。
int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);
代替上面的三个函数,直接一次性编码。

void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
初使化解码上下文。
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl);
对一段内存执行解码,输出解码数据。返回值定义:
-1 出错
0 部分数据在上下文中,需要继续调用EVP_DecodeUpdate或EVP_DecodeFinal。
1 完全处理完成。
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned
char *out, int *outl);
接收余下的解码数据。
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
代替上面的三个函数,直接一次性解码。

使用举例:

下面这个例子同时使用流式和整体方法演示了BASE64编码和解码。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <openssl/evp.h>

namespace dakuang {}

int main(int argc, char* argv[])
{
    {
        printf("use stream EVP method >> \n");

        EVP_ENCODE_CTX* pCtx = EVP_ENCODE_CTX_new();

        const char* pTextSrc = "1234567890abcdefg";
        int nTextSrcLen = strlen(pTextSrc);

        unsigned char* pCipher = (unsigned char*)malloc(nTextSrcLen * 2);
        memset(pCipher, 0, nTextSrcLen * 2);
        int nCipherLen = 0;

        EVP_EncodeInit(pCtx);
        int nOutLen = 0;
        int ret = EVP_EncodeUpdate(pCtx, pCipher + nCipherLen, &nOutLen, (const unsigned char*)pTextSrc, nTextSrcLen);
        printf("encode ret:%d \n", ret);
        printf("encode cipher len:%d body:[%s] \n", nOutLen, pCipher + nCipherLen);
        nCipherLen += nOutLen;
        nOutLen = 0;
        EVP_EncodeFinal(pCtx, pCipher + nCipherLen, &nOutLen);
        printf("encode cipher len:%d body:[%s] \n", nOutLen, pCipher + nCipherLen);
        nCipherLen += nOutLen;

        EVP_ENCODE_CTX_free(pCtx);


        pCtx = EVP_ENCODE_CTX_new();

        unsigned char* pText = (unsigned char*)malloc(nCipherLen);
        memset(pText, 0, nCipherLen);
        int nTextLen = 0;

        EVP_DecodeInit(pCtx);
        nOutLen = 0;
        ret = EVP_DecodeUpdate(pCtx, pText + nTextLen, &nOutLen, (const unsigned char*)pCipher, nCipherLen);
        printf("decode ret:%d \n", ret);
        printf("decode text len:%d body:[%s] \n", nOutLen, pText + nTextLen);
        nTextLen += nOutLen;
        nOutLen = 0;
        //EVP_DecodeFinal(pCtx, pCipher, &nCipherLen);
        EVP_DecodeFinal(pCtx, pText + nTextLen, &nOutLen);
        printf("decode text len:%d body:[%s] \n", nOutLen, pText + nTextLen);
        nTextLen += nOutLen;

        EVP_ENCODE_CTX_free(pCtx);

        free(pCipher);
        free(pText);
    }

    {
        printf("use block EVP method >> \n");

        const char* pTextSrc = "1234567890abcdefg";
        int nTextSrcLen = strlen(pTextSrc);

        unsigned char* pCipher = (unsigned char*)malloc(nTextSrcLen * 2);
        int nCipherLen = EVP_EncodeBlock(pCipher, (const unsigned char*)pTextSrc, nTextSrcLen);
        printf("encode ret:%d \n", nCipherLen);
        printf("cipher:[%s] \n", pCipher);

        unsigned char* pText = (unsigned char*)malloc(nCipherLen);
        int nTextLen = EVP_DecodeBlock(pText, (const unsigned char*)pCipher, nCipherLen);
        printf("decode ret:%d \n", nTextLen);
        printf("text:[%s] \n", pText);

        free(pCipher);
        free(pText);
    }

    return 0;
}

输出:
use stream EVP method >>
encode ret:1
encode cipher len:0 body:[]
encode cipher len:25 body:[MTIzNDU2Nzg5MGFiY2RlZmc=
]
decode ret:0
decode text len:17 body:[1234567890abcdefg]
decode text len:0 body:[]
use block EVP method >>
encode ret:24
cipher:[MTIzNDU2Nzg5MGFiY2RlZmc=]
decode ret:18
text:[1234567890abcdefg]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 根据个人项目经验:在项目中,使用RSA加密,用到的是RSA和Base64和SHA1。Base64进行编码。RSA进...
    王正魁阅读 2,669评论 0 0
  • 大数一般指的是位数很多的数。计算机表示的数的大小是有限的,精度也是有限的,它不能支持大数运算。密码学中采用了很多大...
    大匡先生阅读 4,265评论 0 1
  • 一、总体说明 1.打开ijkplayer,可看到其主要目录结构如下: tool - 初始化项目工程脚本 confi...
    laixh阅读 2,299评论 0 0
  • hash表 数据结构:使用链表数组实现 相关接口 内存分配 内存相关数据结构 内存操作相关接口 CRYPTO_me...
    镜中无我阅读 682评论 0 0
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,991评论 0 3

友情链接更多精彩内容