3.3 編碼/解碼演算法
眾所周知,計算機儲存和處理的都是二進位制資料。為了簡潔,實際上使用最多的是二進位制的一個變種——十六進位制。比如筆者 的名字叫嘉文,中文拼音是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,使用者就會理解了。總結一下:
下面的幾節將討論用文字來表示十六進位制資料的幾種編碼方式。
3.3.1 Base64
這是一種用64個字元來表示任意二進位制資料的方法,通常exe、jpg、pdf等檔案都是二進位制檔案,用文字編輯器開啟都是亂碼,那麼就需要一個方法,可以將二進位制編碼成字串的格式,這樣可以將二進位制檔案用文字開啟檢視。
那麼,既然是Base64,就是通過64個字元來編碼的,具體是哪64個字元呢?請見下表:
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
相關文章
- python教程3.3:字元和編碼Python字元
- Unicode編碼解碼Unicode
- Javascript編碼解碼URLJavaScript
- Go JSON編碼與解碼?GoJSON
- URL編碼與解碼原理
- OpenLR 的編碼與解碼
- python中的編碼&解碼Python
- 設計模式【3.3】-- CGLIB動態代理原始碼解讀設計模式CGLib原始碼
- 音視訊編解碼 -- 編碼引數 CRFCRF
- 解碼返回Unicode編碼的文字Unicode
- 【Netty】編解碼器Netty
- Spring MVC 中文編碼亂碼解決SpringMVC
- Unicode編碼解碼的全面介紹Unicode
- PHP編碼gzdeflate與Golang解碼DEFLATEPHPGolang
- ptyon 特殊處理 url 編碼與解碼,字元編碼轉化 unicode字元Unicode
- 區塊鏈100講:16進位制資料的編碼/解碼演算法區塊鏈演算法
- 網頁地址編碼解碼(網頁地址明文密文轉換)url編碼解碼 Python3網頁Python
- RS編碼和糾錯演算法演算法
- netty系列之:自定義編碼解碼器Netty
- 編解碼器軟體支援 WMP,因為它使用 Directshow 編解碼器
- springmvc-原始碼除錯-3.3-initHandlerAdaptersSpringMVC原始碼除錯APT
- 功能強大的程式碼編輯工具:RubyMine 2022 .3.3中文啟用版
- 什麼是Netty編解碼,Netty編解碼器有哪些?Protostuff怎麼使用?Netty
- Netty原始碼分析之自定義編解碼器Netty原始碼
- JS、C#中URL編碼解碼問題JSC#
- 用JS進行Base64編碼、解碼JS
- 演算法科普:有趣的霍夫曼編碼演算法
- 密碼學基礎:編碼方式、訊息摘要演算法、加密演算法總結密碼學演算法加密
- Dubbo原始碼分析(六)Dubbo通訊的編碼解碼機制原始碼
- IDEA如何設定編碼格式,字元編碼,全域性編碼和專案編碼格式Idea字元
- Flutter Gzip 編碼與解碼 Dart Gzip 工具類操作FlutterDart
- Rust中字串的base64編碼與解碼Rust字串
- Python3內建模組之json編碼解碼方法講解PythonJSON
- 演算法社會:“碼農”翻身為“編碼精英”帶來的思考?演算法
- 音訊編碼基礎詳解音訊
- Netty常用招式——ChannelHandler與編解碼Netty
- 影像壓縮編碼碼matlab實現——行程編碼Matlab行程
- 影像壓縮編碼碼matlab實現——DM編碼Matlab