現在的位置: 首頁 > 綜合 > 正文

base64編碼原理簡介

2014年03月05日 ⁄ 綜合 ⁄ 共 3837字 ⁄ 字號 評論關閉

為什麼叫Base64編碼?
該編碼使用64個明文來編碼任意的二進制文件,它裡面只使用了A-Z,a-z,0-9,+,/這64個字符。編碼裡面還有“=”號啊,不過等號不屬於編碼字符,而是填充字符。

        為什麼發明這麼個編碼?
這個編碼的原理是很簡單的,“破解”也很容易,電子郵件剛出來的時候,只傳遞英文字符,這沒有問題,但是後來,中國人,日本人都要發email,這樣問題就來了,因為這些字符有可能會被郵件服務器或者網關當成命令處理,故必須得有一種編碼來對郵件進行加密,但是加密的目的是為了能夠使得一些原始的服務器不出問題,這樣加密必須得簡單。加密簡單,這樣客戶端程序加密解密也快,又要是明文Ascii編碼,這樣Base64就誕生了。當初設計人員主要是考慮了兩個問題:
1、加密算法複雜程度和效率
2、如何處理傳輸
        算法詳解:
  Base64編碼要求把3個8位字節(3*8=24)轉化為4個6位的字節(4*6=24),之後在6位的前面補兩個0,形成8位一個字節的形式。
例子:
  字符串“張3”
  11010101 11000101 00110011
  從右開始順序選6個數之後在這個六個數之前添加兩個0。,之後再選出6個來,再添加0,依此類推,直到24個二進制數全部被選完。
得到以下結果:
00110101 00011100 00010100 00110011
通過BASE64編碼表得到編碼結果:
00110101   00011100   00010100   00110011
十進制53   十進制34   十進制20   十進制51
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A   17 R    34 i      51 z
1 B    18 S    35 j      52 0
2 C    19 T    36 k     53 1
3 D    20 U    37 l     54 2
4 E     21 V    38 m    55 3
5 F     22 W   39 n    56 4
6 G      23 X   40 o     57 5
7 H      24 Y   41 p     58 6
8 I        25 Z    42 q    59 7
9 J       26 a     43 r      60 8
10 K    27 b     44 s     61 9
11 L     28 c     45 t      62 +
12 M    29 d    46 u     63 /
13 N     30 e     47 v    (pad) =
14 O     31 f      48 w
15 P 32 g 49 x
16 Q 33 h 50 y
這樣,最後的2個字節被整理成了“1iU=”。
同理,若原代碼只剩下一個字節,那麼將會添加兩個“=”。只有這兩種情況,所以,Base64的編碼最多會在編碼結尾有兩個“=”
至於將Base64的解碼,只是一個簡單的編碼的逆過程。
-base64的編碼都是按字符串長度,以每3個8bit的字符為一組,
-然後針對每組,首先獲取每個字符的ASCII編碼,
-然後將ASCII編碼轉換成8bit的二進制,得到一組3*8=24bit的字節
-然後再將這24bit劃分為4個6bit的字節,並在每個6bit的字節前面都填兩個高位0,得到4個8bit的字節
-然後將這4個8bit的字節轉換成10進制,對照Base64編碼表 (下表),得到對應編碼後的字符。

(註:1. 要求被編碼字符是8bit的,所以須在ASCII編碼範圍內,\u0000-\u00ff,中文就不行。
   2. 如果被編碼字符長度不是3的倍數的時候,則都用0代替,對應的輸出字符為=)

Base64 編碼表
Value Char   Value Char   Value Char   Value Char
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

比如舉下面2個例子:
a) 字符長度為能被3整除時:比如“Tom” :

複製代碼
            T           o           m
ASCII:      84          111         109
8bit字節:   01010100    01101111    01101101
6bit字節:     010101      000110      111101      101101
十進制:     21          6           61          45
對應編碼:   V           G           9           t  
複製代碼

所以,btoa('Tom') = VG9t

b) 字符串長度不能被3整除時,比如“Lucy”:

複製代碼
            L           u           c           y
ASCII:      76          117         99          121
8bit字節:   01001100    01110101    01100011    01111001      00000000    00000000
6bit字節:     010011      000111      010101      100011      011110  010000  000000  000000
十進制:     19          7           21          35             30      16      (異常) (異常)      
對應編碼:   T           H           V           j               e       Q       =       =
複製代碼

由於Lucy只有4個字母,所以按3個一組的話,第二組還有兩個空位,所以需要用0來補齊。這裡就需要注意,因為是需要補齊而出現的0,所以轉化成十進制的時候就不能按常規用base64編碼表來對應,所以不是a, 可以理解成為一種特殊的“異常”,編碼應該對應“=”。

有了上面的理論,那我們實現一個base64編碼就容易了。

複製代碼
/**
 * base64 encoding & decoding
 * for fixing browsers which don't support Base64 | btoa |atob
 */

(function (win, undefined) {
 
     var Base64 = function () {
        var base64hash = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
        
        // btoa method
        function _btoa (s) {
            if (/([^\u0000-\u00ff])/.test(s)) {
                throw new Error('INVALID_CHARACTER_ERR');
            }    
            var i = 0,
                prev,
                ascii,
                mod,
                result = [];

            while (i < s.length) {
                ascii = s.charCodeAt(i);
                mod = i % 3;

                switch(mod) {
                    // 第一個6位只需要讓8位二進制右移兩位
                    case 0:
                        result.push(base64hash.charAt(ascii >> 2));
                        break;
                    //第二個6位 = 第一個8位的後兩位 + 第二個8位的前4位
                    case 1:
                        result.push(base64hash.charAt((prev & 3) << 4 | (ascii >> 4)));
                        break;
                    //第三個6位 = 第二個8位的後4位 + 第三個8位的前2位
                    //第4個6位 = 第三個8位的後6位
                    case 2:
                        result.push(base64hash.charAt((prev & 0x0f) << 2 | (ascii >> 6)));
                        result.push(base64hash.charAt(ascii & 0x3f));
                        break;
                }

                prev = ascii;
                i ++;
            }

            // 循環結束後看mod, 為0 證明需補3個6位,第一個為最後一個8位的最後兩位後面補4個0。另外兩個6位對應的是異常的“=”;
            // mod為1,證明還需補兩個6位,一個是最後一個8位的後4位補兩個0,另一個對應異常的“=”
            if(mod == 0) {
                result.push(base64hash.charAt((prev & 3) << 4));
                result.push('==');
            } else if (mod == 1) {
                result.push(base64hash.charAt((prev & 0x0f) << 2));
                result.push('=');
            }

            return result.join('');
        }

        // atob method
        // 逆轉encode的思路即可
        function _atob (s) {
            s = s.replace(/\s|=/g, '');
            var cur,
                prev,
                mod,
                i = 0,
                result = [];

            while (i < s.length) {
                cur = base64hash.indexOf(s.charAt(i));
                mod = i % 4;

                switch (mod) {
                    case 0:
                        //TODO
                        break;
                    case 1:
                        result.push(String.fromCharCode(prev << 2 | cur >> 4));
                        break;
                    case 2:
                        result.push(String.fromCharCode((prev & 0x0f) << 4 | cur >> 2));
                        break;
                    case 3:
                        result.push(String.fromCharCode((prev & 3) << 6 | cur));
                        break;
                        
                }

                prev = cur;
                i ++;
            }

            return result.join('');
        }

        return {
            btoa: _btoa,
            atob: _atob,
            encode: _btoa,
            decode: _atob
        };
    }();

    if (!win.Base64) { win.Base64 = Base64 }
    if (!win.btoa) { win.btoa = Base64.btoa }
    if (!win.atob) { win.atob = Base64.atob }

 })(window)

抱歉!評論已關閉.