【轉】Base64算法詳解

原文連接:https://blog.csdn.net/robertcpp/article/details/51628647html

  完整的BASE64定義可見RFC 1421RFC 2045。編碼後的數據比原始數據略長,爲原來的4/3。在電子郵件中,根據RFC 822規定,每76個字符,還須要加上一個回車換行。能夠估算編碼後數據長度大約爲原長的135.1%。算法

  轉換的時候,將三個byte的數據,前後放入一個24bit的緩衝區中,先來的byte佔高位。數據不足3byte的話,於緩衝器中剩下的bit用0補足。而後,每次取出6(由於26=64)個bit,按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符做爲編碼後的輸出。不斷進行,直到所有輸入數據轉換完成。tcp

  當原數據長度不是3的整數倍時, 若是最後剩下一個輸入數據(原始數據按3個一組,剩下一個),在編碼結果後加2個「=」;若是最後剩下兩個輸入數據(原始數據按3個一組,剩下兩個),編碼結果後加1個「=」;若是沒有剩下任何數據,就什麼都不要加,這樣才能夠保證數據還原的正確性。ui

例子

舉例來講,一段引用自托馬斯·霍布斯利維坦》的文句:this

Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.

通過Base64編碼以後變成:編碼

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=
  • 編碼「Man」
文本 M a n
ASCII編碼 77 97 110
二進制位 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
索引 19 22 5 46
Base64編碼 T W F u

在此例中,Base64算法將三個字符編碼爲4個字符加密

Base64索引表:spa

數值 字符   數值 字符   數值 字符   數值 字符
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 /

  若是要編碼的字節數不能被3整除,最後會多出1個或2個字節,那麼能夠使用下面的方法進行處理:先使用0字節值在末尾補足,使其可以被3整除,而後再進行Base64的編碼。在編碼後的Base64文本後加上一個或兩個'='號,表明補足的字節數。也就是說,當最後剩餘一個八位字節(一個byte)時,最後一個6位的Base64字節塊有四位是0值,最後附加上兩個等號;若是最後剩餘兩個八位字節(2個byte)時,最後一個6位的base字節塊有兩位是0值,最後附加一個等號。 參考下表:.net

文本(1 Byte) A    
二進制位 0 1 0 0 0 0 0 1                                
二進制位(補0) 0 1 0 0 0 0 0 1 0 0 0 0                        
Base64編碼 Q Q    
文本(2 Byte) B C  
二進制位 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1     x x x x x x
二進制位(補0) 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 x x x x x x
Base64編碼 Q k M  

public
class Base64 { /** * 將原始數據編碼爲base64編碼 */ static public char[] encode(byte[] data) { char[] out = new char[((data.length + 2) / 3) * 4]; for (int i = 0, index = 0; i < data.length; i += 3, index += 4) { boolean quad = false; boolean trip = false; int val = (0xFF & (int) data[i]); val <<= 8; if ((i + 1) < data.length) { val |= (0xFF & (int) data[i + 1]); trip = true; } val <<= 8; if ((i + 2) < data.length) { val |= (0xFF & (int) data[i + 2]); quad = true; } out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)]; val >>= 6; out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)]; val >>= 6; out[index + 1] = alphabet[val & 0x3F]; val >>= 6; out[index + 0] = alphabet[val & 0x3F]; } return out; } /** * 將base64編碼的數據解碼成原始數據 */ static public byte[] decode(char[] data) { int len = ((data.length + 3) / 4) * 3; if(data.length > 0 && data[data.length - 1] == '=') --len; if(data.length > 1 && data[data.length - 2] == '=') --len; byte[] out = new byte[len]; int shift = 0; int accum = 0; int index = 0; for(int ix = 0; ix < data.length; ix++) { int value = codes[data[ix] & 0xFF]; if(value >= 0) { accum <<= 6; shift += 6; accum |= value; if(shift >= 8) { shift -= 8; out[index++] = (byte)((accum >> shift) & 0xff); } } } if(index != out.length) throw new Error("miscalculated data length!"); return out; } static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray(); static private byte[] codes = new byte[256]; static { for (int i = 0; i < 256; i++) codes[i] = -1; for (int i = 'A'; i <= 'Z'; i++) codes[i] = (byte) (i - 'A'); for (int i = 'a'; i <= 'z'; i++) codes[i] = (byte) (26 + i - 'a'); for (int i = '0'; i <= '9'; i++) codes[i] = (byte) (52 + i - '0'); codes['+'] = 62; codes['/'] = 63; } public static void main(String[] args) throws Exception { //加密成base64 String strSrc = "林"; String strOut = new String(Base64.encode(strSrc.getBytes())); System.out.println(strOut); String strOut2 = new String(Base64.decode(strOut.toCharArray())); System.out.println(strOut2); } }
相關文章
相關標籤/搜索