Java加密解密(二) Base64編碼

1. Base64的由來

Base64最先用於解決電子郵件傳輸問題。因爲「歷史問題」,早期的電子郵件網關只容許傳輸ASCII(二進制爲00000000-01111111)字符,若是有非ASCII字符通過這種網關時, 字符的二進制位可能會被篡改(如將10000001改成00000001)。由此產生了Base64編碼來保證非ASCII字符的傳輸。html

2. 原理

Base64顧名思義是一種基於64個字符的編碼算法。 以下是Base64的字符映射表,詳情參見RFC 2045java

|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| |14|O||31|f||48|w||(pad)|=| |15|P||32|g||49|x| |16|Q||33|h||50|y|算法

其中的value是10進制的值,Encoding是與之相對應的編碼字符apache

由於Base64中共有64個字符,因此只須要6個bit就能夠表示一個base64字符(1<<6=64)。另外,因爲計算機基本處理單位爲字節,因此字符編碼是以字節爲單位對字符進行編碼,好比,字符'A'的ASCII編碼爲01000001,漢字'你'的UTF-8編碼爲11100100 10111101 10100000, GBK編碼爲11000100 11100011。由此,Base64的編碼步驟以下: step1 將待轉碼字符串以某種編碼格式(如UTF-8)進行編碼,獲得一個字節數組 step2 將字節數組按三個字節爲一組進行分組(24個bit) step3 將每一個分組按6 bit進行劃分(不足6位時低位補0),獲得N(2<=N<=4)個6位二進制碼(如下稱爲Base64編碼單元)。 step4 將每一個Base64編碼單元轉換爲10進制值,並根據上表獲得相應的Base64編碼字符,不足4個編碼單元的分組要用=進行填充。數組

例:oracle

Base64編碼過程 -
原始字符串 我x
UTF-8編碼,分組 0xe6, 0x88, 0x91; 0x78
二進制表示 11100110, 10001000, 10010001; 01111000
劃分編碼單元 111001,101000,100010,010001; 011110,00 00000(補位)
Value 57,40,34,17; 30,0
對應Encoding 5,o,i,R; e,A, =,=(填充符)
最終結果 5oiReA==

3. 用途

  1. 保存二進制數據,如密鑰等。
  2. 使用Http協議在url中傳輸二進制數據。 將Base64編碼中不符合URL規定的字符替換成其餘合法的字符,並去掉回車換行就獲得了UrlBase64編碼。通過UrlBase64編碼,就能夠將二進制參數直接放在url中。 這些功能也能夠用hex編碼實現,但base64編碼的結果要比hex結果短。

4. 實現

jdk中的類sun.misc.BASE64Encodersun.misc.BASE64Decoder提供了Base64的編碼解碼實現,但jdk中sun開頭的包是sun公司的內部實現,該包下的代碼不保證與其餘jave平臺的兼容性(見Why Developers Should Not Write Programs That Call 'sun' Packages),因此須要使用第三方實現,也可將這兩個類複製到本身的代碼中。 筆者測試環境中使用的maven依賴以下:maven

<!--bouncycastle依賴-->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk16</artifactId>
        <version>1.46</version>
    </dependency>
    <!--commons-codec-->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>

4.1 BouncyCastle實現

org.bouncycastle.util.encoders下提供了工具類Base64,UrlBase64與Hex用於Base64,UrlBase64與hex編碼/解碼操做。工具

final String charset="UTF-8";
String input="Base64編/解碼";
//編碼
String encoded=new String(Base64.encode(input.getBytes(charset)),"ASCII");
String urlSafeEncoded=new String(UrlBase64.encode(input.getBytes(charset)),"ASCII");
//解碼
Assert.assertEquals(input,new String(Base64.decode(encoded),charset));
Assert.assertEquals(input,new String(UrlBase64.decode(urlSafeEncoded),charset));

4.2 commons-codec實現

工具類org.apache.commons.codec.binary.Base64提供了Base64與UrlBase64的編碼解碼方法。測試

final String charset="UTF-8";
String input="Base64編/解碼";
String encoded= Base64.encodeBase64String(input.getBytes(charset));
String urlSafeEncoded=Base64.encodeBase64URLSafeString(input.getBytes(charset));
Assert.assertEquals(input, new String(Base64.decodeBase64(encoded), charset));
Assert.assertEquals(input, new String(Base64.decodeBase64(urlSafeEncoded), charset));

4.3 BouncyCastle與commons-codec區別

標準Base64編碼後的字符串每76個字符爲一行(稱爲分塊),行尾要添加一個回車換行符"\r\n"。但bouncycastle並無這樣作,而commons-codec支持標準實現,但默認並無使用。編碼

++++++++++++ BouncyCastle commons-codec
標準(分塊)編碼 不支持 Base64.encodeBase64ChunkedBase64.encodeBase64(binaryData, true)
UrlBase64 沒有回車換行,'+'變爲'-', '/'變爲'_', '='變爲'.' 與bouncyCastle相同,但去掉了填充符
相關文章
相關標籤/搜索