Base64编码/解码原理及实现

前两天在做一个项目时,合作方的开发人员说需要用到Base64 编码。由于之前没听说过这种编码,马上上网google 了下资料,才发现Base64 编码使用得这么普遍,最常用的就是电子邮件传输编码方式。进一步查找资料发现,迅雷的下载地址链接也使用这种编码方式。

      引用维基百科中对Base64 编码的介绍如下:

      “MIME 格式的电子邮件中,base64 可以用来将binary 的字节序列数据编码成ASCII 字符序列构成的文本。使用时,在传输编码方式中指定base64 。使用的字符包括大小写字母各26 个,加上 10 个数字,和加号「+ 」,斜杠「 / 」,一共 64 个字符,等号「= 」用来作为后缀用途。

       完整的base64 定义可见  RFC 1421  RFC 2045。编码后的数据比原始数据略长,为原来的4/3 。在电子邮件中,根据RFC 822规定,每76 个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%

      转换的时候,将三个byte 的数据,先后放入一个24bit 的缓冲区中,先来的byte 占高位。数据不足3byte 的话,于缓冲区中剩下的bit 0 补足。然后,每次取出6 (因为 26 = 64 )个bit ,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。如果最后剩下两个输入数据,在编码结果后加 1 个「 = 」;如果最后剩下一个输入数据,编码结果后加2 个「 = 」;如果没有剩下任何数据,就什么都不要加,这样才可以保证数据还

原的正确性。

      知道了编码的原理后,又上网搜索了有没开源的lib 可用,发现网站libb64: Base64 Encoding/Decoding Routines下已有完整的编码/ 解码源代码可用,下载下来对某一通过Base64 编码的字串进行解码,顺利通过了。试了下编码的功能,发现编码得到的字串在末尾总与标准有差异,查看了源代码,发现其编码并没有按照标准进行。

      于是,马上冒出了自己重写Base64 编码的C 语言代码的念头(后来索性把解码也重新实现了一遍),就当是巩固移位运算的操作吧。虽然编码/ 解码的原理比较简单,但实现完了还是比较开心的,下面把自己实现的编码/ 解码的代码贴出来:

// file: base64_encode.c
const int CHARS_PER_LINE = 76;
int base64_encode(unsigned char *src, long len, char *dest)
{
    const char *encode_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    char *ori_dest = dest;
    int i = 0, step_count = 0;
    int n, r;
    while (i + 3 <= len)
    {
        n = *(src + i) << 16;
        n |= *(src + i + 1) << 8;
        n |= *(src + i + 2);
        *(dest++) = encode_table[(n & 0x00FC0000) >> 18];
        *(dest++) = encode_table[(n & 0x0003F000) >> 12];
        *(dest++) = encode_table[(n & 0x00000FC0) >> 6];
        *(dest++) = encode_table[(n & 0x0000003F)];
        if (++step_count == CHARS_PER_LINE / 4)
        {
            step_count = 0;
            *(dest++) = '/n';
        }
        i += 3;
    }
    if (r = len % 3)
    {
        if (r == 1)
        {
            n = *(src + i) << 16;
            *(dest++) = encode_table[(n & 0x00FC0000) >> 18];
            *(dest++) = encode_table[(n & 0x0003F000) >> 12];
            *(dest++) = '=';
            *(dest++) = '=';
        }
        if (r == 2)
        {
            n = *(src + i) << 16;
            n |= *(src + i + 1) << 8;
            *(dest++) = encode_table[(n & 0x00FC0000) >> 18];
            *(dest++) = encode_table[(n & 0x0003F000) >> 12];
            *(dest++) = encode_table[(n & 0x00000FC0) >> 6];
            *(dest++) = '=';
        }
        if (++step_count == CHARS_PER_LINE / 4)
        {
            *(dest++) = '/n';
        }
    }
    *dest = '/0';
    return dest - ori_dest;
}
// file: base64_decode.c
#include <string.h>
#include <ctype.h>
static long check_length(char *src)
{
    char *p = strchr(src, '=');
    if (p == NULL)
        return strlen(src);
    else
        return p - src;
}
static char base64_decode_digit(char ch)
{
    switch (ch)
    {
    case '+':
        return 62;
    case '/':
        return 63;
    default:
        if (isdigit(ch))
            return ch - '0' + 52;
        else if (islower(ch))
            return ch - 'a' + 26;
        else if (isupper(ch))
            return ch - 'A';
    }
    return 0xFF;
}
int base64_decode(char *src, unsigned char *dest)
{
    int i = 0, n, r;
    long len;
    unsigned char *ori_dest = dest;
    len = check_length(src);
    while (i + 4 <= len)
    {
        n = base64_decode_digit(*(src + i)) << 18;
        n |= base64_decode_digit(*(src + i + 1)) << 12;
        n |= base64_decode_digit(*(src + i + 2)) << 6;
        n |= base64_decode_digit(*(src + i + 3));
        *(dest++) = n >> 16;
        *(dest++) = (n >> 8) & 0xFF;
        *(dest++) = n & 0xFF;
        if (*(src + i + 4) == '/n')
            i++;
        i += 4;
    }
    if (r = len % 4)
    {
        if (r == 2)
        {
            n = base64_decode_digit(*(src + i)) << 18;
            n |= base64_decode_digit(*(src + i + 1)) << 12;
            *(dest++) = n >> 16;
        }
        if (r == 3)
        {
            n = base64_decode_digit(*(src + i)) << 18;
            n |= base64_decode_digit(*(src + i + 1)) << 12;
            n |= base64_decode_digit(*(src + i + 2)) << 6;
            *(dest++) = n >> 16;
            *(dest++) = (n >> 8) & 0xFF;
        }
    }
    *dest = '/0';
    return dest - ori_dest;
}

        用C语言实现编码/解码的功能后,对任意一字串进行编码后与网站(站长工具)https://tool.chinaz.com/Tools/Base64.aspx(一个在线测试Base64编码的网站)下编码的结果进行比较,发现是一样的。又对编码后的字串进行解码,也顺利还原了:)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值