Loading

base64 编码和解码

base64 背景

Base64 是一种用 64 个可打印字符(ASCII字符)来表示任意二进制数据的编码方式。

这 64 个字符包括:'A-Z'(大写)、'a-z'(小写)、'0-9'(数字),外加 '+' 和 '/',用作填充的 '='。

注意:这里的 '=' 不算64个字符里面。'=' 是一个辅助符号,它不在索引表中(索引表里没有它的位置,它不代表任何 6 bit 的数值)

它的本质不是加密,而是一种“翻译”规则,把原本乱码似的二进制(比如图片、压缩包)转成由这些常见字母数字组成的字符串。

早期互联网传输的核心是文件,例如:电子邮件协议最初也只设计用于传输的 ASCII字符 。ASCII 只使用一个字节的低7位(bit6 ~ bit0),这包括了字母、数字等等。如果出现了中文等非英文字符时,问题就出现了。这些数据包含大量 "不可见" 的控制字符(bit7 被使用,值 128~255)。

base64 编码

现代计算机中,“中”字采用 UTF-8 编码,其十六进制字节为:E4 B8 AD,对应的二进制是:11100100 10111000 10101101。

问题来了:这三个字节的最高位都是 1,它们不属于ASCII的可打印范围(0-127)。当老旧的邮件服务器看到这些字节时,会认为它们“非法”,直接粗暴地把最高位砍掉(置0),变成:01100100 (d) 、00111000 (8)、00101101 (-),接收方看到的就会是乱码 "d8-",原始信息彻底丢失。

Base64 把这些“高危”二进制位,重新翻译成绝对安全的字母和数字:

  1. 原始二进制(24 bit):
    11100100 10111000 10101101

  2. 按6bit重新分组(拆成4组):

111001 → 十进制 57 → 查表得 5

001011 → 十进制 11 → 查表得 L

100010 → 十进制 34 → 查表得 i

101101 → 十进制 45 → 查表得 t

  1. 最终Base64编码结果: 5Lit

原本包含高位乱码风险的 E4 B8 AD,经过Base64转换,变成了完全由ASCII可见字符组成的 5Lit

base64 使用

  • linux
#include <openssl/bio.h>

int base64_encode(const uint8_t *in, char *out, int length)
{
    BIO *bmem = NULL;
    BIO *b64 = NULL;
    BUF_MEM *bptr;
    int count = 0;
    b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, in, length);
    BIO_flush(b64);
    BIO_get_mem_ptr(b64, &bptr);
    BIO_set_close(b64, BIO_NOCLOSE);

    count = bptr->length;
    memcpy(out, bptr->data, bptr->length);
    out[bptr->length] = 0;
    BIO_free_all(b64);

    return count;
}
  • esp32
#include "mbedtls/base64.h"

static int base64_decode(char *in_str, int in_len, char *out_str, size_t out_str_size)
{
    int size = 0;
    int ret = 0;
    size_t out_len = 0;
    size_t src_len = in_len;
    unsigned char *src = (unsigned char *)in_str;

    if (in_str == NULL || out_str == NULL || in_len <= 0)
    {
        return -1;
    }

    ret = mbedtls_base64_decode((unsigned char *)out_str, 
                                out_str_size, 
                                &out_len, 
                                (const unsigned char *)in_str, in_len);
    if (0 != ret)
    {
        return -1;
    }

    out_str[out_len] = '\0';
    size = (int)out_len;
    return size;
}
posted @ 2026-07-10 11:26  eiSouthBoy  阅读(27)  评论(0)    收藏  举报