Base64编码解码

一,Base64编码原理

Base64编码的字符数组如下所示 :

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

字符串转Base64编码:取3字节的字符串转换为四字节的字符串,依次往后转换。得到Base64编码字符串。具体原理如下:

1,如果需要编码的原串字节数刚好为3的倍数,那么转换规则如下:

以中文字符'严'为例,'严'字的UTF-8编码为:0xE4B8A5 = 11100100 10111000 10101001。即有:

1)UTF-8第一个字节:0xE4 =11100100

2)UTF-8第二个字节:0xB8 =10111000

3)UTF-8第三个字节:0xA5 =10101001


转Base64的过程如下:

1)Base64第一个字节:取UTF-8第一字节的前六位(111001),然后在六位字符前(111001)填充00,既得Base64编码的第一个字节(00111001)。

2)Base64第二个字节:取UTF-8第一字节的最后两位(00),再取UTF-8第二字节的前四位(1011)组成六位字符串001011,然后在组成的六位字符串(001011)前面填充00,既得Base64编码的第二个字节(00001011)

3)Base64第三个字节:取UTF-8第二字节的后四位(1000),再取UTF-8第三字节的前两位(10)组成六位字符串100010,然后在组成的六位字符串(100010)前面填充00,既得Base64编码的第三个字节(00100010)

4)Base64第四个字节:取UTF-8第三字节的后六位(101001),然后在六位字符前(101001)填充00,既得Base64编码的第四个字节(00101001)。


2,如果需要编码的原串字节数最后剩余2,那么转换规则如下:

以字符串"aa"为例,"aa"的UTF-8编码为:0x6161 = 01100001 01100001。既有:

1)UTF-8第一个字节:0x61 = 01100001

2)UTF-8第二个字节:0x61 = 01100001


转Base64的过程如下:

1)Base64第一个字节:取UTF-8第一字节的前六位(011000),然后在六位字符前(011000)填充00,既得Base64编码的第一个字节(00011000)。

2)Base64第二个字节:取UTF-8第一字节的最后两位(01),再取UTF-8第二字节的前四位(0110)组成六位字符串010110,然后在组成的六位字符串(010110)前面填充00,既得Base64编码的第二个字节(00010110)。

3)Base64第三个字节:取UTF-8第二字节的后四位(0001),然后在四位字符(0001)前填充00,得六位字符串(000001),由于此时不够一个字节(八位),再在六位字符串(000001)后面填充00即可,既得Base64编码的第三个字节(00000100)。

4)Base64第四个字节:此时使用字符'='填充即可。


3,如果需要编码的原串字节数最后剩余1,那么转换规则如下:

以字符串"a"为例,"a"的UTF-8编码为:0x61 = 01100001。既有:

1)UTF-8第一个字节:0x61 = 01100001


转Base64的过程如下:

1)Base64第一个字节:取UTF-8第一字节的前六位(011000),然后在六位字符前(011000)填充00,既得Base64编码的第一个字节(00011000)。

2)Base64第二个字节:取UTF-8第一字节的最后两位(01),然后在两位字符(01)前填充00,得四位字符串(0001),由于此时不够一个字节(八位),再在四位字符串(0001)后面填充0000即可,既得Base64编码的第二个字节(00010000)。

3)Base64第三个字节:此时使用字符'='填充即可。

3)Base64第四个字节:此时使用字符'='填充即可。


综上可得编码程序如下:

intbase64_string(constunsignedchar*src,unsignedchar*dest,unsignedchar*base64,intindex){assert(src);unsignedcharone;unsignedchartwo;unsignedcharthr;unsignedcharfou;size_tlen=strlen(src);if(len>=3){one=src[0]>>2;two=((src[0]&0x03)<<4)|(src[1]>>4);thr=((src[1]&0x0F)<<2)|(src[2]>>6);fou=src[2]&0x3F;*(dest+index++)=base64[one];*(dest+index++)=base64[two];*(dest+index++)=base64[thr];*(dest+index)=base64[fou];}elseif(len==2){one=src[0]>>2;two=((src[0]&0x03)<<4)|(src[1]>>4);thr=(src[1]&0x0F)<<2;*(dest+index++)=base64[one];*(dest+index++)=base64[two];*(dest+index++)=base64[thr];*(dest+index)='=';}elseif(len==1){one=src[0]>>2;two=(src[0]&0x03)<<4;*(dest+index++)=base64[one];*(dest+index++)=base64[two];*(dest+index++)='=';*(dest+index)='=';}else{printf("Unknowlength\n");}returnlen>=3?3:len;}voidbase64_encode(constunsignedchar*src,unsignedchar*dest){assert(src);unsignedcharbase64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";intindex=0;while(*src){intstep=base64_string(src,dest,base64,index);index+=4;src+=step;}*(dest+index)='\0';}


二,Base64解码

1,原理

Base64字符串以四字节为一组,转换为三字节的过程。依次类推,直到全部转化完成。

2,数组

由于Base64编码时用到如下所示的字符数组进行转换,字符数组如下:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

由上可知,A在数组的位置为0,故有(A,0),依次类推有(B,1),(C,2)等。故可得如下所示的对应关系:

ABCDEFGHIJ0123456789KLMNOPQRST10111213141516171819UVWXYZabcd20212223242526272829efghijklmn30313233343536373839opqrstuvwx40414243444546474849yz012345675051525354555657585989+/60616263

由于编码时,如果得到的一个字节的值为0那么编码后即为A。相应的,在解码过程中,如果一个字节的值为A,那么转换为0即可。由于A的十进制值为65,而在编码数组的下标为0。既有A-65-0。同理,B的十进制值为66,在编码数组的下标为1,既有B-66-1。

Base64字符所在的区间为A-Z,a-z,0-9,+,/。由上可知,其中的临界值有如下对应关系:

base64字符 - 字符值(解码数组的下标) - 在base64编码数组中的下标

A - 65 - 0

Z - 90 - 25

a - 97 - 26

z - 122 - 51

0 - 48 - 52

9 - 57 - 61

+ - 43 - 62

/ - 47 - 63

一个字节八位,故最大值为2^8 = 256,但由上临界值可知最大值为122,所以实际解码数组定义为124长度即可(0-122存关键信息,123存'\0')。故可得如下数组:

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3F,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,

获取数组的程序如下所示:

voidcreate_array(unsignedchar*array){intindex=0;for(index=0;index<123;index+=1){if(index==0x2B){*(array+index)=0x3E;}elseif(index==0x2F){*(array+index)=0x3F;}elseif(index>=0x30&&index<=0x39){*(array+index)=0x34+index-0x30;}elseif(index==0x3D){/*特殊字符'=',也可合并到else情况*/*(array+index)=0x00;}elseif(index>=0x41&&index<=0x5A){*(array+index)=index-0x41;}elseif(index>=0x61&&index<=0x7A)*(array+index)=0x1A+index-0x61;}else{*(array+index)=0x00;}}*(array+123)='\0';}

3,解码

解码时分三种情况处理:

1)四个字符中最后一个字符为'='的情况,以YWE=为例:

首先将除'='外的字节转换为对应的二进制:

Base64第一个字节:Y :24 = 0001 1000(24是Y对应数组下标的值)

Base64第二个字节:W:22 = 0001 0110

Base64第三个字节:E :4 = 0000 0100


取Base64的第一字节后六位(011000)和Base64第二字节去掉前两位填充位00后(010110)的前两位(01),拼接后既得UTF-8编码的第一个字节(01100001)

取Base64的第二字节后四位(0110)和Base64第三字节去掉前两位填充位00后(000100),再去掉后两位填充位00后(0001),拼接后既得UTF-8编码的第二个字节(01100001)


2)四个字符中最后两个字符为'='的情况,以YQ==为例:

首先将除'='外的字节转换为对应的二进制:

Base64第一个字节:Y :24 = 0001 1000

Base64第二个字节:Q :16 = 0001 0000


取Base64的第一个字节后六位(011000)和Base64第二字节去掉前两位填充位00后(010000),再去掉后四位填充位0000后(01),拼接后即可得UTF-8编码的第一个字节(01100001)


3)四个字符中不包含字符'='的情况,以5Lil为例:

首先将除'='外的字节转换为对应的二进制:

Base64第一个字节:5:57 = 0011 1001

Base64第二个字节:L:11 = 0000 1011

Base64第三个字节:i:34 = 0010 0010

Base64第四个字节:l:37 = 0010 0101


取Base64第一个字节后六位(111001)和Base64第二字节去掉前两位填充位00后的前两位(00),拼接后既得UTF-8编码的第一个字节(11100100)

取Base64第二字节的后四位(1011)和Base64第三字节去掉前两位填充位00后的前四位(1000),拼接后既得UTF-8编码的第二字节(10111000)

取Base64第三字节的后两位(10)和Base64第四字节的后六位(100101),拼接后既得UTF-8编码的第三字节(10100101)


综上可知,解码程序如下:

intdecode_string(constunsignedchar*src,unsignedchar*dest,unsignedchar*array,intindex){assert(src);intstep=0;unsignedcharone;unsignedchartwo;unsignedcharthr;if(src[3]=='='&&src[2]=='='){one=(array[src[0]]<<2)|(array[src[1]]>>4);*(dest+index)=one;step=1;}elseif(src[3]=='='){one=(array[src[0]]<<2)|(array[src[1]]>>4);two=((array[src[1]]&0x0F)<<4)|(array[src[2]]>>2);*(dest+index++)=one;*(dest+index)=two;step=2;}else{one=(array[src[0]]<<2)|(array[src[1]]>>4);two=((array[src[1]]&0x0F)<<4)|(array[src[2]]>>2);thr=(array[src[2]]<<6)|array[src[3]];*(dest+index++)=one;*(dest+index++)=two;*(dest+index)=thr;step=3;}returnstep;}voidbase64_decode(constunsignedchar*src,unsignedchar*dest){assert(src);unsignedchararray[124];memset(array,0x00,124);create_array(array);intindex=0;while(*src){intstep=decode_string(src,dest,array,index);index+=step;src+=4;}*(dest+index)='\0';}

参考文献:http://blog.itpub.net/18903360/viewspace-1985669/