3.3 編碼/解碼演算法

xiaohuanglv發表於2018-08-25

眾所周知,計算機儲存和處理的都是二進位制資料。為了簡潔,實際上使用最多的是二進位制的一個變種——十六進位制。比如筆者 的名字叫嘉文,中文拼音是jiawen(全小寫),在計算機裡儲存的就是6A696177656E。很明顯,人類容易記住jiawen,而其相應的十六進 制程式碼6A696177656E就很考驗人的記憶力了。同樣,人類很難記住十六進位制的資料,但如果是十六進位制編碼的文字字串,就相對好記好讀一些了。以 下是一張ASCII碼錶的一部分。


DEC  OCT  HEX    BIN         Symbol   HTML Number   HTML Name Description
0    000   00    00000000    NUL      �        Null char
1    001   01    00000001    SOH              Start of Heading
2    002   02    00000010    STX              Start of Text
3    003   03    00000011    ETX              End of Text
4    004   04    00000100    EOT              End of Transmission
5    005   05    00000101    ENQ              Enquiry
6    006   06    00000110    ACK              Acknowledgment
7    007   07    00000111    BEL              Bell
8    010   08    00001000    BS               Back Space
9    011   09    00001001    HT       	        Horizontal Tab
10   012   0A    00001010    LF       
        Line Feed
11   013   0B    00001011    VT               Vertical Tab
...
47   057   2F    00101111    /        /         Slash or divide
48   060   30    00110000    0        0         Zero
49   061   31    00110001    1        1         One
50   062   32    00110010    2        2         Two
51   063   33    00110011    3        3         Three
52   064   34    00110100    4        4         Four
53   065   35    00110101    5        5         Five
54   066   36    00110110    6        6         Six
55   067   37    00110111    7        7         Seven
56   070   38    00111000    8        8         Eight
57   071   39    00111001    9        9         Nine
58   072   3A    00111010    :        :         Colon
...
70   106   46    01000110    F        F         Uppercase F
71   107   47    01000111    G        G         Uppercase G
72   110   48    01001000    H        H         Uppercase H
73   111   49    01001001    I        I         Uppercase I
74   112   4A    01001010    J        J         Uppercase J
75   113   4B    01001011    K        K         Uppercase K
76   114   4C    01001100    L        L         Uppercase L
77   115   4D    01001101    M        M         Uppercase M
78   116   4E    01001110    N        N         Uppercase N
79   117   4F    01001111    O        O         Uppercase O
80   120   50    01010000    P        P         Uppercase P
81   121   51    01010001    Q        Q         Uppercase Q
82   122   52    01010010    R        R         Uppercase R
www.ascii-code.com 6A696177656E


十六進位制的07是一個Bell(響鈴),如果試著用計算機程式去列印,結果是不可見,也不可理解的,只能聽到一聲 鈴聲。但是文字字串"07"則相對容易理解和記憶。上文提到過,比特幣地址都是十六進位制的數,不做轉換,列印的話毫無意義,人類無法直觀地辨識。大家可 以想象一下查詢自己的銀行賬戶餘額的場景:假如賬戶裡只有77塊錢了,查詢結果列印的是大寫字元M(十進位制的編碼是77)。我相信大部分使用者都不知道那是 77的意思。相對的,如果把數字77轉換成文字“77”(其十六進位制編碼是3737)後再列印,對於顯示在螢幕上的文字77,使用者就會理解了。總結一下:

image.png

下面的幾節將討論用文字來表示十六進位制資料的幾種編碼方式。

3.3.1 Base64

這是一種用64個字元來表示任意二進位制資料的方法,通常exe、jpg、pdf等檔案都是二進位制檔案,用文字編輯器開啟都是亂碼,那麼就需要一個方法,可以將二進位制編碼成字串的格式,這樣可以將二進位制檔案用文字開啟檢視。

那麼,既然是Base64,就是通過64個字元來編碼的,具體是哪64個字元呢?請見下表:

image.png

Base64編碼主要用在傳輸、儲存、表示二進位制等領域,還可以用來加密。但是這種加密比較簡單,只是一眼看上去不知道什麼內容罷了,對應編碼規則,可以很容易的解碼,當然也可以對Base64的字元序列進行定製來進行加密,我們來看下Base64的編碼過程。

首先,既然是使用上述64個字元的範圍來表示的,那麼要能夠表示出64個字元的各種組合,得起碼用6個bit才 行,根據排列組合,6個bit可以總共表示出26個組合的字元排列;針對一份需要轉化的二進位制檔案,可以這樣來處理,每3個位元組一組,這樣一共是 24bit,然後可以針對這個24bit再來劃分,劃分成每6bit一組,這樣一共可以分成4組,則對照上表去查詢對應的字元就可以了,這樣就可以轉換為 Base64了,簡單吧。

那麼,如果在3個位元組一組劃分的時候,如果不是3的倍數怎麼辦呢?這樣就需要使用\x00位元組在末尾補足,再在編碼的末尾加上1個或2個=號,表示補了多少位元組。

由於標準的Base64編碼後可能出現字元+和/,在URL中就不能直接作為引數,所以又有一種url safe的Base64編碼,其實就是把字元+和/分別變成-和_。

根據這個原理,其實還是比較容易理解這種編碼思想的,而且也可以看出,這種編碼是可以逆向的,以"yes"這個字串為例,它的Base64編碼是eWVz,大家可以自行嘗試幾個例子。

3.3.2 Base58

顧名思義,Base58是基於58個字母和數字組成的,有了Base64的基礎,我們就比較容易理解Base58了,實際上就是Base64的一個子集,相對於Base64來說,Base58不包括以下Base64的字元:

·數字0

·大寫字母O

·大寫字母I

·小寫字母l

·+與/

可以看出,小寫o和大寫O很容易和數字0混淆,小寫l和大寫I很容易和數字1混淆,Base58就是Base64去除了幾個看起來容易混淆的字元,以及容易導致轉義的/和+。Base58的編碼表如下:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

必須注意,不同的應用實現使用的編碼表內容是一樣的,但是順序可能不一樣,比如:

1)比特幣地址:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz;

2)Ripple地址:rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz。

接下來我們來了解一下Base58Check,比特幣使用的是改進版的Base58演算法,是為了解決Base58編碼的字串沒有完整性校驗機制。在傳播過程中,如果出現某些字元損壞或者遺漏,就沒法檢測出來了,所以使用了改進版的演算法Base58Check。

3.3.3 Base58Check

在二進位制資料的傳輸過程中,為了防止資料傳輸的錯誤,保護資料安全,通常會加一個校驗碼,通過校驗碼的配合可以發 現資料是否被破壞或者是否在傳送時輸入錯誤了。Base58Check就是Base58加上校驗碼,或者可以說是Base58的一種編碼形式,在比特幣系 統中生成錢包地址的時候就使用到了這種編碼形式。我們知道,錢包地址是用來轉賬的,雖然Base58編碼已經可以做到避免一些容易混淆的字元,但是還不能 保證使用者的誤輸入或者地址資訊在傳輸過程中由於某種原因被損壞,這會給使用者帶來潛在的損失風險。

Base58Check的編碼方式,在我們第1章中介紹比特幣地址的時候已經提到過,它的編碼方式是這樣的:進行 編碼前,在待編碼的內容字串中加入一個位元組的版本資訊,版本資訊可以自行約定,比如比特幣地址採用了0x00作為版本資訊,然後再加入待編碼內容字串 的雜湊值,通常只要取得雜湊值中的4個位元組就可以了,加到一起後,然後再整體進行Base58編碼。比特幣地址的生成過程中,是將版本位元組放在了頭部,而 將4個位元組的雜湊值放在了尾部,然後進行編碼生成。這個原理還是很簡單的,雜湊演算法具有先天的資料完整性檢測能力,在這裡我們又看到了雜湊演算法的又一個應 用。

經過整體編碼後的資料在傳輸過程中如果有發生損壞或者篡改,接收方在得到資料後,會對原始資料進行同樣的校驗碼計 算,並且和接收到的結果中的校驗碼進行比較。由於雜湊演算法的特點,只要原始資料有任何更改,計算出的雜湊值都會發生變更,因此只要校驗碼不一致就說明資料 不是合法的。

來源:我是碼農,轉載請保留出處和連結!

本文連結:http://www.54manong.com/?id=102

'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646208", container: s }); })();
'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646147", container: s }); })();

相關文章