BASE64编码是一种常用的将十六进制数据转换为可见字符的编码。与ASCII码相比,它占用的空间较小。BASE64编码在rfc3548中定义。
1、base64编解码原理
关于这个编码的规则:
1)把3个字符变成4个字符
2)每76个字符加一个换行符
3)最后的结束符也要处理
将数据编码成BASE64编码时,3字符转4字符后,每个字符6bit,得到一个数字:0-63。但是由于0-63中有很多不可打印字符,需要进行二次映射,映射的规则就是
0~25:A~Z
26~51:a~z
52~61:0~9
62:+
63:/
比如有数据:0x30 0x82 0x02
编码过程如下:
1)得到16进制数据: 30 82 02
2)得到二进制数据: 00110000 10000010 00000010
3)每6bit分组: 001100 001000 001000 000010
4)得到数字: 12 8 8 2
5)根据查表得到结果 : M I I C
BASE64填充:在不够的情况下在右边加0。
有三种情况:
1) 输入数据比特数是24的整数倍(输入字节为3字节整数倍),则无填充;
2) 输入数据最后编码的是1个字节(输入数据字节数除3余1),即8比特,则需要填充2个"==",因为要补齐6比特,需要加2个00;
3)输入数据最后编码是2个字节(输入数据字节数除3余2),则需要填充1个"=",因为补齐6比特,需要加一个00。
举例如下:
对0x30编码:
1) 0x30的二进制为:00110000
2) 分组为:001100 00
3) 填充2个00:001100 000000
4) 得到数字:12 0
5) 查表得到的编码为MA,另外加上两个==
所以最终编码为:MA==
2、Base64编解码,下面代码参考开源软件cyassl:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {
BAD = 0xFF, /* invalid encoding */
PAD = '=',
PEM_LINE_SZ = 64
};
static
const char base64Decode[] = { 62, BAD, BAD, BAD, 63, /* + starts at 0x2B */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
BAD, BAD, BAD, BAD, BAD, BAD, BAD,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25,
BAD, BAD, BAD, BAD, BAD, BAD,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51
};
int Base64Decode(const char* in, int inLen, char * out, int * outLen)
{
int i = 0;
int j = 0;
while (inLen > 3) {
char b1, b2, b3;
char e1 = in[j++];
char e2 = in[j++];
char e3 = in[j++];
char e4 = in[j++];
int pad3 = 0;
int pad4 = 0;
if (e1 == 0) /* end file 0's */
break;
if (e3 == PAD)
pad3 = 1;
if (e4 == PAD)
pad4 = 1;
e1 = base64Decode[e1 - 0x2B];
e2 = base64Decode[e2 - 0x2B];
e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
b1 = (e1 << 2) | (e2 >> 4);
b2 = ((e2 & 0xF) << 4) | (e3 >> 2);
b3 = ((e3 & 0x3) << 6) | e4;
out[i++] = b1;
if (!pad3)
out[i++] = b2;
if (!pad4)
out[i++] = b3;
else
break;
inLen -= 4;
if (in[j] == ' ' || in[j] == '/r' || in[j] == '/n') {
char endLine = in[j++];
inLen--;
while (endLine == ' ') { /* allow trailing whitespace */
endLine = in[j++];
inLen--;
}
if (endLine == '/r') {
endLine = in[j++];
inLen--;
}
if (endLine != '/n')
return -1;
}
}
*outLen = i;
return 0;
}
static
const char base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '/'
};
int Base64Encode(const char* in, int inLen, char * out, int* outLen)
{
int i = 0,j = 0,n = 0; /* new line counter */
int outSz = (inLen + 3 - 1) / 3 * 4;
if (outSz > *outLen) return -1;
while (inLen > 2) {
char b1 = in[j++];
char b2 = in[j++];
char b3 = in[j++];
/* encoded idx */
char e1 = b1 >> 2;
char e2 = ((b1 & 0x3) << 4) | (b2 >> 4);
char e3 = ((b2 & 0xF) << 2) | (b3 >> 6);
char e4 = b3 & 0x3F;
/* store */
out[i++] = base64Encode[e1];
out[i++] = base64Encode[e2];
out[i++] = base64Encode[e3];
out[i++] = base64Encode[e4];
inLen -= 3;
if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen)
out[i++] = '/n';
}
/* last integral */
if (inLen) {
int twoBytes = (inLen == 2);
char b1 = in[j++];
char b2 = (twoBytes) ? in[j++] : 0;
char e1 = b1 >> 2;
char e2 = ((b1 & 0x3) << 4) | (b2 >> 4);
char e3 = (b2 & 0xF) << 2;
out[i++] = base64Encode[e1];
out[i++] = base64Encode[e2];
out[i++] = (twoBytes) ? base64Encode[e3] : PAD;
out[i++] = PAD;
}
//out[i++] = '/n';
if (i != outSz)
return -1;
*outLen = outSz;
return 0;
}
int main()
{
char * sstr = "123Hello987World+=%456";
char encrystr[256];
int len = 256;
memset(encrystr,'/0',256);
Base64Encode(sstr,strlen(sstr),encrystr, &len);
printf("estr : %s/n",encrystr);
printf("\n");
printf("This is encode");
printf("\n");
char decrystr[256];
memset(decrystr,'/0',256);
Base64Decode(encrystr,len,decrystr,&len);
printf("dstr : %s/n",decrystr);
scanf("%d",&len);
return 0;
}