Base64编码原理及编码、解码实现

一、Base64编码原理

1、Base64编码原理简单介绍

Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。编码原理如下所示:

(1)base64的编码都是按字符串长度,以每3个8bit的字符为一组,

(2)然后针对每组,首先获取每个字符的ASCII编码,

(3)然后将ASCII编码转换成8bit的二进制,得到一组3*8=24bit的字节

(4)然后再将这24bit划分为4个6bit的字节,并在每个6bit的字节前面都填两个高位0,得到4个8bit的字节

(5)然后将这4个8bit的字节转换成10进制,对照Base64编码表,得到对应编码后的字符。

2、Base64编码表

Base64编码使用64个明文来编码任意的二进制文件,它里面只使用了A-Z,a-z,0-9,+,/这64个字符。编码里面还有“=”号,不过等号不属于编码字符,而是填充字符。Base64编码表如下所示:

3、一个简单的实例

以字符串“Ow!”为例:

(1)字符串“Ow!”被分拆成3个8位的字节(0x4F、0x77、0x21);

(2)这3个字节构成一个24位的二进制值:01001111 01110111 00100001;

(3)这些位被划分为4个6位的序列:010011、110111、011100、100001;

(4)每个6bit的字节前面都填两个高位0,得到4个8bit的字节:00010011、00110111、00011100、00100001;

(5)这4个8bit的字节对应的10进制的数值分别为:19、55、28、33,对照Base64编码表,得到对应编码后的字符:T、3、c、h。到此编码结束。

4、Base64编码填充机制

Base64编码收到一个8位字节序列,将这个二进制序列划分成6位的快。二进制序列有时不能正好平分成6位的块,在这种情况下,就在序列末尾填充零位,使二进制的序列成为24的倍数(6和8的最小公倍数)。

对已填充的二进制串进行编码时,任何完全填充(不包含原始数据中位)的6位组都由特殊的第65个字符“=”表示。如果6位组是部分填充的,就将填充位设置为0。一个实例如下表所示:


“a:a”和“a:aaaa”分别为3个字节和6个字节,是3的倍数,因此无需填充。“a:aa”和“a:aaa”分别为4个字节和5个字节,不是3的倍数,因此需要填充。

二、Base64编码与解码实现

下面的实现来自Android的Base.cpp文件。在其他平台用需要做适当的修改。

sp<ABuffer> decodeBase64(const AString &s) {
    if ((s.size() % 4) != 0) {
        return NULL;
    }

    size_t n = s.size();
    size_t padding = 0;
    if (n >= 1 && s.c_str()[n - 1] == '=') {
        padding = 1;

        if (n >= 2 && s.c_str()[n - 2] == '=') {
            padding = 2;
        }
    }

    size_t outLen = 3 * s.size() / 4 - padding;

    sp<ABuffer> buffer = new ABuffer(outLen);

    uint8_t *out = buffer->data();
    size_t j = 0;
    uint32_t accum = 0;
    for (size_t i = 0; i < n; ++i) {
        char c = s.c_str()[i];
        unsigned value;
        if (c >= 'A' && c <= 'Z') {
            value = c - 'A';
        } else if (c >= 'a' && c <= 'z') {
            value = 26 + c - 'a';
        } else if (c >= '0' && c <= '9') {
            value = 52 + c - '0';
        } else if (c == '+') {
            value = 62;
        } else if (c == '/') {
            value = 63;
        } else if (c != '=') {
            return NULL;
        } else {
            if (i < n - padding) {
                return NULL;
            }

            value = 0;
        }

        accum = (accum << 6) | value;

        if (((i + 1) % 4) == 0) {
            out[j++] = (accum >> 16);

            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 
            if (j < outLen) { out[j++] = accum & 0xff; }

            accum = 0;
        }
    }

    return buffer;
}

static char encode6Bit(unsigned x) {
    if (x <= 25) {
        return 'A' + x;
    } else if (x <= 51) {
        return 'a' + x - 26;
    } else if (x <= 61) {
        return '0' + x - 52;
    } else if (x == 62) {
        return '+';
    } else {
        return '/';
    }
}

void encodeBase64(const void *_data, size_t size, AString *out) {
    out->clear();

    const uint8_t *data = (const uint8_t *)_data;

    size_t i;
    for (i = 0; i < (size / 3) * 3; i += 3) {
        uint8_t x1 = data[i];
        uint8_t x2 = data[i + 1];
        uint8_t x3 = data[i + 2];

        out->append(encode6Bit(x1 >> 2));
        out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
        out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
        out->append(encode6Bit(x3 & 0x3f));
    }
    switch (size % 3) {
        case 0:
            break;
        case 2:
        {
            uint8_t x1 = data[i];
            uint8_t x2 = data[i + 1];
            out->append(encode6Bit(x1 >> 2));
            out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
            out->append(encode6Bit((x2 << 2) & 0x3f));
            out->append('=');
            break;
        }
        default:
        {
            uint8_t x1 = data[i];
            out->append(encode6Bit(x1 >> 2));
            out->append(encode6Bit((x1 << 4) & 0x3f));
            out->append("==");
            break;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值