base16、base32和base64轉碼原理

base16、base32和base64,轉碼原理

基本概念

ASCII 是用128(2的8次方)個字符,對二進制數據進行編碼的方式
base64編碼是用64(2的6次方)個字符,對二進制數據進行編碼的方式
base32就是用32(2的5次方)個字符,對二進制數據進行編碼的方式
base16就是用16(2的4次方)個字符,對二進制數據進行編碼的方式

基於base16編解碼源碼介紹

就是把二進制數據轉成16進制,顯示16進制的值就可以了
16進制一個字符是4位,正常一個字節是8位,切一半就轉成16進制了。
所以,base16轉碼後空間擴大一倍,4位轉成一個字符, 1個字節轉成兩個字符

#include <iostream>
using namespace std;
static const char BASE16_ENC_TAB[] = "0123456789ABCDEF";
//  '0' ~'9' =>  48~57  'A'~'F' = > 65~70
static const char BASE16_DEC_TAB[128] = {
    -1,                                 //0
    -1,-1,-1,-1,-1, -1,-1,-1,-1,-1,      //1-10
    -1,-1,-1,-1,-1, -1,-1,-1,-1,-1,      //11-20
    -1,-1,-1,-1,-1, -1,-1,-1,-1,-1,      //21-30
    -1,-1,-1,-1,-1, -1,-1,-1,-1,-1,      //31-40
    -1,-1,-1,-1,-1, -1,-1, 0, 1, 2,      //41-50
    3, 4, 5, 6 ,7,  8, 9, -1,-1,-1,      //51-60
    -1,-1,-1,-1,10, 11,12,13,14,15      //61-70 'A'~'F'
};

int Base16Encode(const unsigned char* in, int size, char* out)
{
    for (int i = 0; i < size; i++)
    {
        //一個字節取出高4位和低4位  1000 0001  0000 1000
        char h = in[i] >> 4;   //移位丟棄低位,右移4位  (0~15)
        char l = in[i] & 0x0F; // 0000 1111 去掉高位 (0~15)
        out[i * 2] = BASE16_ENC_TAB[h]; //(0~15) 映射到對應字符
        out[i * 2 + 1] = BASE16_ENC_TAB[l];
    }
    //base16 轉碼後空間擴大一倍 4位轉成一個字符 1個字節轉成兩個字符
    return size * 2;
}

int Base16Decode(const string &in, unsigned char* out)
{
    //講兩個字符拼成一個字節  B2E2CAD442617365313600
    for (int i = 0; i < in.size(); i += 2)
    {
        unsigned char ch = (int)in[i];           //高位轉換的字符 'B'=>66 :10
        unsigned char cl = (int)in[i + 1];       //低位轉換的字符 '2'=>50 :2
        unsigned char h = BASE16_DEC_TAB[ch];   //轉換成原來的值
        unsigned char l = BASE16_DEC_TAB[cl];

        // 兩個4位拼成一個字節(8位)
        ///  1000  >>4    1000 0000
        //   0001         0000 0001
        //               |1000 0001
        out[i / 2] = (int)(h << 4 | l);
    }
    return in.size() / 2;
}

int main(int argc,char *argv[])
{
    cout << "Test Base16" << endl;
    const unsigned char data[] = "測試Base16";
    int len = sizeof(data);
    char out1[1024] = { 0 };
    unsigned char out2[1024] = { 0 };
    cout << data << endl;
    int re = Base16Encode(data, len, out1);
    cout << re << ":" << out1 << endl;
    re = Base16Decode(out1, out2);
    cout << re << ":" << (char*)out2 << endl;

    return 0;
}

輸出結果
image.png
解碼的時候’b’字符轉換成ASCII碼值位66,所以66位改爲10的值。


image.png

Base-64編碼

Encoding VS. Encryption

很多人都以爲編碼(Encoding)和加密(Encryption)是同一個意思。編碼和加密都是對格式的一種轉換,但是它們是有區別的。編碼是 公開的,比如下面要介紹的Base 64編碼,任何人都可以解碼;而加密則相反,你只希望自己或者特定的人才可以對內容進行解密。

作用及原理

Base 64 Encoding有什麼用?舉個簡單的例子,你使用SMTP協議 (Simple Mail Transfer Protocol 簡單郵件傳輸協議)來發送郵件。因爲這個協議是基於文本的協議,所以如果郵件中包含一幅圖片,我們知道圖片的存儲格式是二進制數據(binary data),而非文本格式,我們必須將二進制的數據編碼成文本格式,這時候Base 64 Encoding就派上用場了。

Base64編碼的作用:由於某些系統中只能使用ASCII字符。Base64就是用來將非ASCII字符的數據轉換成ASCII字符的一種方法。它使用下面表中所使用的字符與編碼。


而且base64特別適合在http,mime協議下快速傳輸數據。


base64其實不是安全領域下的加密解密算法。雖然有時候經常看到所謂的base64加密解密。其實base64只能算是一個編碼算法,對數據內容進行編碼來適合傳輸。雖然base64編碼過後原文也變成不能看到的字符格式,但是這種方式很初級,很簡單。

X.509公鑰證書也好,電子郵件數據也好,經常要用到Base64編碼,那麼爲什麼要作一下這樣的編碼呢?
我們知道在計算機中任何數據都是按ascii碼存儲的,而ascii碼的128~255之間的值是不可見字符。而在網絡上交換數據時,比如說從A地傳到B地,往往要經過多個路由設備,由於不同的設備對字符的處理方式有一些不同,這樣那些不可見字符就有可能被處理錯誤,這是不利於傳輸的。所以就先把數據先做一個Base64編碼,統統變成可見字符,這樣出錯的可能性就大降低了。

如一個xml當中包含另一個xml數據,此時如果將xml數據直接寫入顯然不合適,將xml進行適當編碼存入較爲方便,事實上xml當中的字符一般都是可見字符(0-127之間),但是由於中文的存在,可能存在不可見字符,直接將字符打印在外層xml的數據中顯然不合理,那麼怎麼辦呢?
可以使用base64進行編碼,然後存入xml,解碼反之
其實還有個辦法,將byte的值寫在xml當中,空格或者,分開,這樣也可以將byte數據傳入,不過這樣更浪費空間,並且不易保存.


另一個,比如http協議當中的key value字段,必須進行URLEncode 不然出現的等號可能使解析失敗 空格也會使http請求解析出現問題,比如 請求行就是以空格來劃分的 POST /guowuxin/hehe HTTP/1.1


又比如有些文本協議不支持不可見字符的傳遞,只能用大於32的可見字符來傳遞信息(協議規定)

索引表

base64索引表:

image.png

base32索引表:

image.png

base16索引表:

image.png


轉碼原理

轉碼

這裏只介紹Base-64轉碼,其他的原理一樣
2的6次方即爲64
Base-64編碼將一個8位子節序列拆散爲6位的片段,併爲每6位分配一個字符(見索引表)。這64個字符都是很常見的,可以安全地放在HTTP首部字段中。這64個字符中包括大小寫字母、數字、+和/,特殊字符=(即結尾處使用的=號)


示例:
image.png
在結尾還差的補等於號。


上面的三個字符“Man”是原文,下面的四個字符“TWFu”是Base64編碼後的字符


經過base64編碼後,字符串理論上比之前長1/3,也就是原來的4/3。(除下面兩種情況外)。

base64填充

base64編碼收到一個8bit字節數據,將這個二進制序列每6bit劃分一個塊。二進制序列有時不能正好平均地分爲6位的塊,在這種情況下,就在序列末尾填充零位,使二進制序列的長度成爲24的倍數(6和8的最小公倍數)。

  • 6bit裏面的數據,全部是填充的,它顯示的符號是第65個符號”=”。
  • 6bit裏面的數據,部分是填充的,按照索引表正常顯示

示例:

輸入字符串爲”a:a”爲3個字節(24位)。24是24的倍數,因此按照上面給出的例子計算。無需填充就會得到base64編碼爲”YTph”。


輸入字符串變爲”a:aa”爲4個字節(32位)。要湊爲24的倍數,最小的值是48。因此要添加16個填充碼。


a:a – 011000 010011 101001 100001 – YTph
a:aa – 011000 010011 101001 100001 011000 01xxxx xxxxxx xxxxxx – YTphYQ==
a:aaa – 011000 010011 101001 100001 011000 010110 0001xx xxxxxx – YTphYWE=
a:aaaa – 011000 010011 101001 100001 011000 010110 000101 1000001 – YTphYWFh

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章