Base64是最常见的用于传输8Bit字节码的编码方式之一,它是一种基于64个可打印字符来表示二进制数据的方法。
Base64是什么
Base64编码,是由64个字符组成编码集:26个大写字母A~Z,26个小写字母a~z,10个数字0~9,符号“ ”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节,然后根据Base64的对应表,得到对应的编码数据。
当原始数据凑不够三个字节时,编码结果中会使用额外的符号“=”来表示这种情况。
Base64编码表
码值 | 字符 | 码值 | 字符 | 码值 | 字符 |
---|---|---|---|---|---|
0 | A | 26 | a | 52 | 0 |
1 | B | 27 | b | 53 | 1 |
2 | C | 28 | c | 54 | 2 |
3 | D | 29 | d | 55 | 3 |
4 | E | 30 | e | 56 | 4 |
5 | F | 31 | f | 57 | 5 |
6 | G | 32 | g | 58 | 6 |
7 | H | 33 | h | 59 | 7 |
8 | I | 34 | i | 60 | 8 |
9 | J | 35 | j | 61 | 9 |
10 | K | 36 | k | 62 |
|
11 | L | 37 | l | 63 | / |
12 | M | 38 | m | ||
13 | N | 39 | n | ||
14 | O | 40 | o | ||
15 | P | 41 | p | ||
16 | Q | 42 | q | ||
17 | R | 43 | r | ||
18 | S | 44 | s | ||
19 | T | 45 | t | ||
20 | U | 46 | u | ||
21 | V | 47 | v | ||
22 | W | 48 | w | ||
23 | X | 49 | x | ||
24 | Y | 50 | y | ||
25 | Z | 51 | z |
Base64编码步骤
- 将原始数据按照每三个字节作为一组进行划分,每组一共是24个二进制位。
- 再将这24个二进制位,每6个一划分,分为四组(6×4=24个二进制位)。
- 然后在每组前面补上00,扩展成8×4=32个二进制位,即四个字节(因为每个字节前面有2个0,所以每个字节的最大值是63)。
- 最后根据Base64编码表,将这四个字节的码值,转换为对应的Base64的字符即可。
Base64编码过程举例
情况1:正常的3个字节编码
将单词“PCB”转换为Base64编码:
- "P"、"C"、"B"的ASCII值分别是80、67、66,对应的二进制值是0101 0000、0100 0011、0100 0010,将它们连成一个24位的二进制字符串010100000100001101000010。
- 将这个24位的二进制字符串,每6个一组分成4组:010100、000100、001101、000010。
- 在每组前面加两个00,扩展成32个二进制位,即四个字节:00010100、00000100、00001101、00000010。它们的十进制值分别是19、22、5、46。(最前面加上两个0只是为了凑成一个字节,实际上其本身的数值是没有变化的)
- 根据上表,得到每个值对应Base64编码,即U、E、N、C。
情况2:剩余2个字节编码
对于2个字节(16个二进制数)的情况,比如将“PC”转换为Base64编码:
转换方法同上,区别在于:
- 16个二进制数,每6个一组分割,最后剩余4个,这时再在后面补两个0凑成6个。
- 然后还按照基础的方法转换,最后补一个“=”即可
转换过程如下表,最终将“PC”转换为了“UEM=”
情况3:剩余1个字节编码
对于12个字节(8个二进制数)的情况,比如将“P”转换为Base64编码:
转换方法同上,区别在于:
- 16个二进制数,每6个一组分割,最后剩余2个,后面要再补4个0
- 然后还按照基础的方法转换,最后补两个“=”即可
转换过程如下表,最终将“P”转换为了“UA==”
Base64编解码C程序
编码程序
编码的程序设计思路,就是按照上面讲解的编码过程,每3个原始字符为一组,进行编码,得到4个base64的字符。对于不够3个字符的情况,编码的base64的字符后面补上一到两个=
号。
#include <stdio.h>
#include <string.h>
/*base64符号表*/
const char *base64Arr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /";
/*base64增补符号*/
const char paddingChar = '=';
/** @func: base64_encode
* @brief: base64编码
* @para: [srcData]:要进行编码的原始数据
* [resBase64]:base64编码结果
* @return:none
*/
void base64_encode(const unsigned char * srcData, char * resBase64)
{
int i=0; /*原始数据索引*/
int j=0; /*base64结果索引*/
unsigned char transIdx=0; // 索引是8位,但是高两位都为0
const int srcLen = strlen((const char*)srcData);
/*每3个一组,进行编码*/
for(i=0; i < srcLen; i =3)
{
/*取出第1个字符的高6位*/
transIdx = ((srcData[i] >> 2) & 0x3f); /*0011 1111*/
/*查表*/
resBase64[j ] = base64Arr[(int)transIdx];
/*取出第1个字符的低2位*/
transIdx = ((srcData[i] << 4) & 0x30); /*0011 0000*/
/*第1个字符后面还有字符*/
if (i 1 < srcLen)
{
/*取出第2个字符的高4位,并与第1个字符的低2位进行组合*/
transIdx |= ((srcData[i 1] >> 4) & 0x0f); /*0000 1111*/
/*查表*/
resBase64[j ] = base64Arr[(int)transIdx];
}
else /*第1个字符后面没有字符了*/
{
/*直接使用第1个字符的低2位查表*/
resBase64[j ] = base64Arr[(int)transIdx];
/*然后补上两个=号*/
resBase64[j ] = paddingChar;
resBase64[j ] = paddingChar;
break; /*没有数据了,break结束*/
}
/*取出第2个字符的低4位*/
transIdx = ((srcData[i 1] << 2) & 0x3c); /*0011 1100*/
/*第2个字符后面还有字符*/
if (i 2 < srcLen)
{
/*取出第3个字符的高2位,并与第2个字符的低4位进行组合*/
transIdx |= ((srcData[i 2] >> 6) & 0x03); /*0000 0011*/
/*查表*/
resBase64[j ] = base64Arr[(int)transIdx];
/*取出第3个字符的低6位*/
transIdx = srcData[i 2] & 0x3f; /*0011 1111*/
/*查表*/
resBase64[j ] = base64Arr[(int)transIdx];
}
else /*第2个字符后面没有字符了*/
{
/*直接使用第2个字符的低4位查表*/
resBase64[j ] = base64Arr[(int)transIdx];
/*然后补上一个=号*/
resBase64[j ] = paddingChar;
break; /*没有数据了,break结束*/
}
}
/*结束符*/
resBase64[j] = '