「 加密 」Base64
一. 簡介
首先有個小Tips,1個字母字元 = 1個位元組(byte) = 8位(bit),這是表示單位.
Base64
是網路上最常見的用於傳輸 8bit 的編碼方式之一,Base64就是一種基於64個可列印字元來表示二進位制資料的方法。
在一些網路傳送渠道,有時候有些的位元組字元不能被支援.比如圖片的二進位制流的每個位元組不可能全部是可見字元,這種情況下傳送不了.而Base64的機制就能很好解決這種問題,它不改變原來的協議,在原來的基礎做一種擴充套件,基於64個可列印字元來表示二進位制.
再者,有時候我們通過記事本去開啟一些圖片或者應用程式,會得到一大堆看不懂的亂碼,因為二進位制檔案裡面有很多無法顯示和列印的字元.所以如果要讓記事本能夠處理二進位制資料,就可以使用Base64來進行轉碼,將不可見的轉成可見的.
二. 演算法原理
- 我們拿到一串字元,比如 abcdef.先按ASCII碼編碼.
- 它會將字串按位元組數分開,每三個位元組為一組. 3 byte * 8 bit === 24bit.
- 在這組中,將24位資料按照每6位為一組,再次分成4組.
- 然後將這四組的6位數的高位各補兩個0,將其轉為十進位制數.
- 進行查表,得到對應的字元,就是對應的Base64轉化的字元.
那麼有個問題來了,如果原始資料的位數不是3的整數倍怎麼辦,Base會在不足的後面用"="補足,所以這個"="只會存在在Base64碼的最後,並且只會有1或者2個,不可能出現在中間.
// javaScript實現 if (!Shotgun) var Shotgun = {}; if (!Shotgun.Js) Shotgun.Js = {}; Shotgun.Js.Base64 = { _table: [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' ], encode: function (bin) { var codes = []; var un = 0; un = bin.length % 3; if (un == 1) bin.push(0, 0); else if (un == 2) bin.push(0); for (var i = 2; i < bin.length; i += 3) { var c = bin[i - 2] << 16; c |= bin[i - 1] << 8; c |= bin[i]; codes.push(this._table[c >> 18 & 0x3f]); codes.push(this._table[c >> 12 & 0x3f]); codes.push(this._table[c >> 6 & 0x3f]); codes.push(this._table[c & 0x3f]); } if (un >= 1) { codes[codes.length - 1] = "="; bin.pop(); } if (un == 1) { codes[codes.length - 2] = "="; bin.pop(); } return codes.join(""); }, decode: function (base64Str) { var i = 0; var bin = []; var x = 0, code = 0, eq = 0; while (i < base64Str.length) { var c = base64Str.charAt(i++); var idx = this._table.indexOf(c); if (idx == -1) { switch (c) { case '=': idx = 0; eq++; break; case ' ': case '\n': case "\r": case '\t': continue; default: throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u65E0\u6548\u7F16\u7801\uFF1A" + c }; } } if (eq > 0 && idx != 0) throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u683C\u5F0F\u9519\u8BEF\uFF01" }; code = code << 6 | idx; if (++x != 4) continue; bin.push(code >> 16); bin.push(code >> 8 & 0xff); bin.push(code & 0xff) code = x = 0; } if (code != 0) throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u6570\u636E\u957F\u5EA6\u9519\u8BEF" }; if (eq == 1) bin.pop(); else if (eq == 2) { bin.pop(); bin.pop(); } else if (eq > 2) throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u683C\u5F0F\u9519\u8BEF\uFF01" }; return bin; } };
三. 應用
- Base64編碼可用於在HTTP環境下傳遞較長的標識資訊.
- 電子郵件:有些文字協議不支援不可見字元的傳遞,只能用大於32的可見字元來傳遞資訊
- Base64 也會經常用作一個簡單的“加密”來保護某些資料,而真正的加密通常都比較繁瑣.
- 垃圾訊息傳播者用Base64來避過反垃圾郵件工具,因為那些工具通常都不會翻譯Base64的訊息.
- 前端在實現頁面一些比較小的圖片,通常會選擇將圖片內容直接內嵌在頁面中,避免不必要的外部資源載入,增大頁面載入時間,但是圖片資料是二進位制資料,該怎麼嵌入呢?絕大多數現代瀏覽器都支援一種名為 Data URLs 的特性,允許使用Base64對圖片或其他檔案的二進位制資料進行編碼,將其作為文字字串嵌入網頁中。比如webpack工具中的url-loader預設將8kb以下的圖片編譯成Base64碼嵌在引用檔案中.
四. 前端應用
功能強大,不止處理Base64,支援的模組非常多,star數目前6k+,前後端可用
//後端 npm包管理 npm install crypto-js import sha256 from 'crypto-js/sha256'; import hmacSHA512 from 'crypto-js/hmac-sha512'; import Base64 from 'crypto-js/enc-base64'; const message, nonce, path, privateKey; // ... const hashDigest = sha256(nonce + message); const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey)); //前端 Brower管理 bower install crypto-js
專門處理Base64,目前star數2k+,前後端均可用
//安裝 $ npm install --save js-base64 //如果你使用的es6語法,需要轉載這個進行語法轉換 $ npm install --save babel-preset-env //node.js var Base64 = require('js-base64').Base64; //es6+ import { Base64 } from 'js-base64'; //非常輕快的使用體驗 Base64.encode('dankogai');// ZGFua29nYWk= Base64.encode('小飼弾');// 5bCP6aO85by+ Base64.encodeURI('小飼弾'); // 5bCP6aO85by
五. 解密
如果你看懂了以上的演算法原理,那麼解密其實不是太大的問題,只要你遵循這個規則進行逆推運算,就可以得到原始資料.所以嚴格上說Base64並不是什麼加密,只是編譯過後的並不是明文而已