Base64 编解码的C语言实现

来源:互联网 发布:文华财经期货 for mac 编辑:程序博客网 时间:2024/05/19 16:35

简介

Base64编码是将任何类型的数据转换成ASCII码的可见字符,然后接收端再反向解码,得到原始的数据。最早的的Base是用于发送Email内容的。

经过Base64转换之后的数据大小变大了,为原数据的4/3大小。但是方便了传输,比如由于base64的编码中没有<>等特殊字符,可以不用转义扫描,直接放在XML中,放在MIME中,甚至直接不经过转义扫描存进数据库中。由于有这些方便的特性,即使数据量变大,base64编码还是被广泛使用。


原理

编码原理

每个字节8位,每次取出3个字节,也就是3 x 8 = 24 位。然后每次从此24位中取出6位,然后在前端补2位0,组成新的8位,也就是一个字节。这样就将3个字节转换成了4个字节。由于前面两位都是0,所以转换后的每个字节能表示的最大数字为63, 也就是说转换后的每个字节只可能是0-63中的一个数字。

然后根据规范给出的Base64索引表,将1-63 这64个数字转换成"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"中的一个。

当最后取出3个字节不够时,不够的位置补0,并且最后少一个字节时编码的最后加一个“=”,少两个字节时加两个"="

解码原理

解码是编码的反向过程,每次取出4个字节,然后将每个字节的字符转换成原始Base64索引表对应的索引数字,也就是编码时3字节转换成4字节的转换结果。然后使用位操作将每字节前2位去掉,重新转换成3字节。需要注意的是最后对于结尾“=”的处理。


代码实现

ENCODE:

static char base64_index[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *base64_encode(const char *input, const size_t length, char *output){    *output = '\0';    if (input == NULL || length < 1) return output;    char *p = (char*)input;    char *p_dst = (char*)output;;    char *p_end = (char*)input + length;    int  loop_count = 0;    // 0x30 -> 00110000    // 0x3C -> 00111100    // 0x3F -> 00111111    while (p_end - p >= 3) {        *p_dst++ = base64_index[( p[0] >> 2 )];        *p_dst++ = base64_index[( (p[0] << 4) & 0x30 ) | ( p[1] >> 4 )];        *p_dst++ = base64_index[( (p[1] << 2) & 0x3C ) | ( p[2] >> 6 )];        *p_dst++ = base64_index[p[2] & 0x3F];        p += 3;    }    if (p_end - p > 0) {        *p_dst++ = base64_index[(p[0] >> 2)];        if (p_end - p == 2) {            *p_dst++ = base64_index[( (p[0] << 4) & 0x30 ) | ( p[1] >> 4 )];            *p_dst++ = base64_index[(p[1] << 2) & 0x3C];             *p_dst++ = '=';        } else if (p_end - p == 1) {            *p_dst++ = base64_index[(p[1] << 4) & 0x30];            *p_dst++ = '=';            *p_dst++ = '=';        }    }    *p_dst = '\0';    return output;}

DECODE:

// 16 * 16static int base64_decode_map[256] = {    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0   - 15    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16  - 31    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32  - 47    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48  - 63    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 64  - 79    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80  - 95    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96  - 111    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112 - 127    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128 - 143    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144 - 159     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160 - 175    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176 - 191    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192 - 207    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208 - 223    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224 - 239    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 240 - 255};char *base64_decode(const char* input, char *output){    output[0] = '\0';    if (input == NULL || output == NULL)         return output;    int input_len = strlen(input);    if (input_len < 4 || input_len % 4 != 0)         return output;    // 0xFC -> 11111100    // 0x03 -> 00000011    // 0xF0 -> 11110000    // 0x0F -> 00001111    // 0xC0 -> 11000000    char *p = (char*)input;    char *p_out = output;    char *p_end = (char*)input + input_len;    for (; p < p_end; p += 4) {        *p_out++ = ((base64_decode_map[p[0]] << 2) & 0xFC) | ((base64_decode_map[p[1]] >> 4) & 0x03);        *p_out++ = ((base64_decode_map[p[1]] << 4) & 0xF0) | ((base64_decode_map[p[2]] >> 2) & 0x0F);        *p_out++ = ((base64_decode_map[p[2]] << 6) & 0xC0) | (base64_decode_map[p[3]]);     }    if (*(input + input_len - 2) == '=') {        *(p_out - 2) = '\0';    } else if (*(input + input_len - 1) == '=') {        *(p_out - 1) = '\0';    }    return output;}

代码中的base64_decode_map的作用就是将base64索引中的ASCII字符转换成原始的0-63的数字。


其他

base64在不同的场景也有一个差别,有的编码结果中每76个字符加入一个换行。这也是正确的。以上的代码示例中没有加入,如需加入只需计数,定期加入换行符即可。

编码结果的大小在不加入换行符时是原来长度的4/3,但是需要注意精确malloc内存时,需要 (org_len + 3)  * 4 / 3,如果需要增加结尾的'\0',需要再加1位。或者直接org_len *4 / 3 + 2