編解碼:Base64編解碼
編解碼:十六進制編解碼中提到,編解碼本質上是以不同的資料形式來展示“資訊”,可以用二進制來表示,可以用十六進制來表示。
二進制的資料,在計算機中通常是不可讀、不可列印的。
那有沒有一種方式,可以讓二進制的資料變成“可讀可列印”的?
方法有很多,最常見的是十六進制編解碼和Base64編解碼。
十六進制編解碼之前已介紹過,本文介紹Base64編解碼。
百度百科:Base64是一種基于64個可列印字元來表示二進制資料的方法。
Base64編碼要求把3個8位位元組(3*8=24)轉化為4個6位的位元組(4*6=24),之後在6位的前面補兩個0,形成8位一個位元組的形式。 如果剩下的字元不足3個位元組,則用0填充,輸出字元使用’=’,是以編碼後輸出的文本末尾可能會出現1或2個’=’(隻可能出現0/1/2個等号,否則就是錯誤的)。
為啥隻可能出現0/1/2個等号?動手算算就知道。
将所有的bit位用8n表示(n表示待編碼資料位元組數量),則當:
n=1時,8*1 mod 6 = 2bit,需要補2個等号
n=2時,8*2 mod 6 = 4bit,需要補1個等号
n=3時,8*3 mod 6 = 0bit,需要補0個等号
n=4時,8*4 mod 6 = 2bit,需要補2個等号
……
Base64編解碼前後空間大小變化:
6位元組的資料,在編碼後占用8位元組空間;空間多占用了2B,比原來大:2B/6B=1/3
8位元組的資料,在解碼後占用6位元組空間;空間少占用了2B,比原來小:2B/8B=1/4
Base64編碼使得待編碼資料增大,增加到原大小的4/3;
Base64解碼使得戴潔馬資料減小,減小到原大小的3/4;
Demo:
待轉換資料(3位元組24bit):0x61(a), 0x62(b), 0x63(c):
二進制形式:01100001 01100010 01100011
分組(每6bit一組*4組):011000 010110 001001 100011
每組高位補兩個bit的0:00011000 00010110 00001001 00100011
十進制:24 22 9 35
參照對照表(摘自:http://base64.xpcha.com/):

Base64結果:YWJj
待轉換資料(1位元組8bit):0x61(a)
二進制形式:01100001
不是6bit整數,需要多補4個bit 0,結果為:01100001 0000
分組:011000 010000
高位補兩個bit的0:00011000 00010000
十進制:24 16
轉換結果:Y Q
由于Base64規定,Base64結果長度一定是4的倍數,如果不夠則以’=’補全,則實際Base64結果為:
YQ==
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const unsigned char *base64=(unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/*-----------------------------------------------------------------------------
* 函數名稱:Base64Encode
* 功能描述:Base64編碼
* 參數說明:base64code:編碼結果緩沖區;src:待編碼資料;src_len待編碼資料長度
* 返 回 值:編碼結果長度(位元組)
* 備 注:注意留有足夠的結果緩沖區(src_len/3*4)
* */
static int Base64Encode(char *base64code, const char *src, int src_len)
{
int n,buflen,i,j;
if (src_len == )
src_len = strlen(src);
buflen=n=src_len;
for (i=,j=; i<=buflen-; i+=,j+=)
{
base64code[j] = (src[i]&)>>;
base64code[j+] = ((src[i]&)<<) + ((src[i+]&)>>);
base64code[j+] = ((src[i+]&)<<) + ((src[i+]&)>>);
base64code[j+] = src[i+]&;
}
if (n%==)
{
base64code[j] = (src[i]&)>>;
base64code[j+] = ((src[i]&)<<);
base64code[j+] = ;
base64code[j+] = ;
j += ;
}
else if (n%==)
{
base64code[j] = (src[i]&)>>;
base64code[j+] = ((src[i]&)<<) + ((src[i+]&)>>);
base64code[j+] = ((src[i+]&)<<);
base64code[j+] = ;
j += ;
}
for (i=; i<j; i++)
base64code[i] = base64[(int)base64code[i]];
base64code[j] = ;
return j;
}
/*-------------------------------------------------------------------------------
* 函數名稱:Base64Decode
* 功能描述:Base64解碼
* 參數說明:buf:解碼結果緩沖區;base64code:待解碼資料;src_len:待解碼資料長度
* 返 回 值:解碼結果長度(位元組)
* 備 注:注意,buf中解碼結果緩沖區中資料不一定可列印
* */
static int Base64Decode(char *buf, const char *base64code, int src_len)
{
int n,i,j,pad;
if (src_len == )
src_len = strlen(base64code);
if (src_len% != )
return -;
unsigned char *p=;
unsigned char *src=;
pad = ;
n = src_len;
src = (unsigned char *)malloc(n);
for (i=; i<n; i++)
src[i]=base64code[i];
while (n>&&src[n-]=='=')
{
src[n-] = ;
pad++;
n--;
}
for(i=; i<n; i++)
{
p = (unsigned char *)strchr((const char *)base64, (int)src[i]);
if (!p)
{
free(src);
return -;
}
src[i] = p-(unsigned char *)base64;
}
for (i=,j=; i<n; i+=,j+=)
{
buf[j] = (src[i]<<) + ((src[i+]&)>>);
buf[j+] = ((src[i+]&)<<) + ((src[i+]&)>>);
buf[j+] = ((src[i+]&)<<) + src[i+];
}
j -= pad;
buf[j] = ;
free(src);
return j;
}
int main()
{
// 測試Base64編碼
{
char buff[] = "";
char *str = "0123456789abcdef";
memset(buff, , ); // clear
int base64len = Base64Encode(buff, str, strlen(str));
buff[base64len] = ;
printf("%s\n", buff);
}
// 測試Base64解碼
{
char buff[] = "";
char *str = "MDEyMzQ1Njc4OWFiY2RlZg==";
memset(buff, , );
int base64len = Base64Decode(buff, str, strlen(str));
printf("%s\n", buff);
}
return ;
}
編譯 && 執行:
[jiang@localhost jiang]$ gcc -o Base64 Base64.c
[jiang@localhost jiang]$ ./Base64
MDEyMzQ1Njc4OWFiY2RlZg==
89abcdef
需要注意:
為啥在編碼時需要指明待編碼資料長度?
原因是待編碼資料不一定可讀,是二進制資料,即,可能存在0x00,很顯然不可以用strlen,那我在編碼函數中如何知道其待編碼資料長度呢?不知道!是以,調用編碼函數時需要顯示地指明待編碼資料長度。
引用:
1.http://base64.xpcha.com/