Base64是一種編碼方式,這個術語最初是在「MIME內容傳輸編碼規範」中提出的。Base64不是一種加密算法,它其實是一種「二進制轉換到文本」的編碼方式,它可以將任意二進制數據轉換爲ASCII字符串的形式,以便在只支持文本的環境中也可以順利地傳輸二進制數據。java
(1)base64編碼:把二進制數據轉爲字符算法
(2)base64解碼:把字符轉爲二進制數據apache
由於有些網絡傳輸渠道並不支持全部字節,例如傳統的郵件只支持可見字符的傳輸,像ASCII碼的控制字符(ASCII碼包含了 128 個字符。其中前 32 個, 0-31 ,即 0x00-0x1F ,都是不可見字符。這些字符,就叫作控制字符。)就不能經過郵件傳輸。另外例如圖片二進制流的每一個字節不可能所有都是可見字符,因此就傳送不了。網絡
最好的方法就是在不改變傳統協議的狀況下,作一種擴展方案來支持二進制文件的傳送,把不可能打印的字符用可打印的字符標識,問題就解決了。Base64編碼就應運而生,Base64就是一種基於64個可打印字符來表示二進制數據的表示方法。app
以下圖Base64編碼索引表,字符選用了「A-Z 、 a-z 、 0-九、+、 / 」64個可打印字符。數字表明字符索引,這個是標準Base64標準協議規定的,不能更改。64個字節用6個bit位就能夠所有表示(32+16+8+4+2+1)就能夠所有表示。這裏注意一個Base64字符是8個bit,但有效部分只有右邊6個bit,左邊兩個永遠是0。ide
那麼怎麼用6個有效bit來表示傳統字符的8個bit呢?8和6的最小公倍數是24,也就是說3個傳統字節能夠由4個Base64字符來表示,保證有效位數是同樣的,這樣就多了1/3的字節數來彌補Base64只有6個有效bit的不足。你也能夠說用兩個Base64字符也能表示一個傳統字符,可是採用最小公倍數的方案實際上是最減小浪費的。結合下邊的圖比較容易理解。Man是三個字符,一共24個有效bit,只好用4個Base64字符來湊齊24個有效位。紅框表示的是對應的Base64,6個有效位轉化成相應的索引值再對應Base64字符表,查出"Man"對應的Base64字符是"TWFU"。說到這裏有個原則不知道你發現了沒有,要轉換成Base64的最小單位就是三個字節,對一個字符串來講每次都是三個字節三個字節的轉換,對應的是Base64的四個字節。這個搞清楚了其實就差很少了。測試
可是轉換到最後你發現不夠三個字節了怎麼辦呢?願望終於實現了,咱們能夠用兩個Base64來表示一個字符或用三個Base64表示兩個字符,像下圖的A對應的第二個Base64的二進制位只有兩個,把後邊的四個補0就是了。因此A對應的Base64字符就是QQ。上邊已經說過了,原則是Base64字符的最小單位是四個字符一組,那這才兩個字符,後邊補兩個"="吧。其實不用"="也不耽誤解碼,之因此用"=",多是考慮到多段編碼後的Base64字符串拼起來也不會引發混淆。因而可知Base64字符串只可能最後出現一個或兩個"=",中間是不可能出現"="的。下圖中字符"BC"的編碼過程也是同樣的。this
1 package xin.dreaming.base64; 2 3 import java.io.UnsupportedEncodingException; 4 5 6 public class Base64 { 7 static private final int BASELENGTH = 255; 8 static private final int LOOKUPLENGTH = 64; 9 static private final int TWENTYFOURBITGROUP = 24; 10 static private final int EIGHTBIT = 8; 11 static private final int SIXTEENBIT = 16; 12 static private final int SIXBIT = 6; 13 static private final int FOURBYTE = 4; 14 static private final int SIGN = -128; 15 static private final byte PAD = (byte) '='; 16 static private byte[] base64Alphabet = new byte[BASELENGTH]; 17 static private byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; 18 //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64"); 19 20 static { 21 for (int i = 0; i < BASELENGTH; i++) { 22 base64Alphabet[i] = -1; 23 } 24 for (int i = 'Z'; i >= 'A'; i--) { 25 base64Alphabet[i] = (byte) (i - 'A'); 26 } 27 for (int i = 'z'; i >= 'a'; i--) { 28 base64Alphabet[i] = (byte) (i - 'a' + 26); 29 } 30 for (int i = '9'; i >= '0'; i--) { 31 base64Alphabet[i] = (byte) (i - '0' + 52); 32 } 33 34 base64Alphabet['+'] = 62; 35 base64Alphabet['/'] = 63; 36 37 for (int i = 0; i <= 25; i++) 38 lookUpBase64Alphabet[i] = (byte) ('A' + i); 39 40 for (int i = 26, j = 0; i <= 51; i++, j++) 41 lookUpBase64Alphabet[i] = (byte) ('a' + j); 42 43 for (int i = 52, j = 0; i <= 61; i++, j++) 44 lookUpBase64Alphabet[i] = (byte) ('0' + j); 45 46 lookUpBase64Alphabet[62] = (byte) '+'; 47 lookUpBase64Alphabet[63] = (byte) '/'; 48 } 49 50 public static boolean isBase64(String isValidString) { 51 return isArrayByteBase64(isValidString.getBytes()); 52 } 53 54 public static boolean isBase64(byte octect) { 55 //shall we ignore white space? JEFF?? 56 return (octect == PAD || base64Alphabet[octect] != -1); 57 } 58 59 public static boolean isArrayByteBase64(byte[] arrayOctect) { 60 int length = arrayOctect.length; 61 if (length == 0) { 62 // shouldn't a 0 length array be valid base64 data? 63 // return false; 64 return true; 65 } 66 for (int i = 0; i < length; i++) { 67 if (!Base64.isBase64(arrayOctect[i])) 68 return false; 69 } 70 return true; 71 } 72 73 public static String encode(String str) { 74 if (str == null) 75 return ""; 76 try { 77 byte[] b = str.getBytes("UTF-8"); 78 return new String(encode(b), "UTF-8"); 79 } catch (UnsupportedEncodingException e) { 80 return ""; 81 } 82 } 83 public static byte[] encodeStr2Byte(String str) { 84 if (str == null) 85 return null; 86 try { 87 byte[] b = str.getBytes("UTF-8"); 88 return encode(b); 89 } catch (UnsupportedEncodingException e) { 90 return null; 91 } 92 } 93 94 public static String encodeByte2Str(byte[] bytes) { 95 if (bytes == null) 96 return ""; 97 try { 98 return new String(encode(bytes), "UTF-8"); 99 } catch (UnsupportedEncodingException e) { 100 return null; 101 } 102 } 103 104 105 /** 106 * Encodes hex octects into Base64. 107 * 108 * @param binaryData Array containing binary data to encode. 109 * @return Base64-encoded data. 110 */ 111 public static byte[] encode(byte[] binaryData) { 112 int lengthDataBits = binaryData.length * EIGHTBIT; 113 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 114 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 115 byte encodedData[] = null; 116 117 if (fewerThan24bits != 0) { 118 //data not divisible by 24 bit 119 encodedData = new byte[(numberTriplets + 1) * 4]; 120 } else { 121 // 16 or 8 bit 122 encodedData = new byte[numberTriplets * 4]; 123 } 124 125 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 126 127 int encodedIndex = 0; 128 int dataIndex = 0; 129 int i = 0; 130 //log.debug("number of triplets = " + numberTriplets); 131 for (i = 0; i < numberTriplets; i++) { 132 dataIndex = i * 3; 133 b1 = binaryData[dataIndex]; 134 b2 = binaryData[dataIndex + 1]; 135 b3 = binaryData[dataIndex + 2]; 136 137 //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3); 138 139 l = (byte) (b2 & 0x0f); 140 k = (byte) (b1 & 0x03); 141 142 encodedIndex = i * 4; 143 byte val1 = 144 ((b1 & SIGN) == 0) 145 ? (byte) (b1 >> 2) 146 : (byte) ((b1) >> 2 ^ 0xc0); 147 byte val2 = 148 ((b2 & SIGN) == 0) 149 ? (byte) (b2 >> 4) 150 : (byte) ((b2) >> 4 ^ 0xf0); 151 byte val3 = 152 ((b3 & SIGN) == 0) 153 ? (byte) (b3 >> 6) 154 : (byte) ((b3) >> 6 ^ 0xfc); 155 156 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 157 //log.debug( "val2 = " + val2 ); 158 //log.debug( "k4 = " + (k<<4) ); 159 //log.debug( "vak = " + (val2 | (k<<4)) ); 160 encodedData[encodedIndex + 1] = 161 lookUpBase64Alphabet[val2 | (k << 4)]; 162 encodedData[encodedIndex + 2] = 163 lookUpBase64Alphabet[(l << 2) | val3]; 164 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; 165 } 166 167 // form integral number of 6-bit groups 168 dataIndex = i * 3; 169 encodedIndex = i * 4; 170 if (fewerThan24bits == EIGHTBIT) { 171 b1 = binaryData[dataIndex]; 172 k = (byte) (b1 & 0x03); 173 //log.debug("b1=" + b1); 174 //log.debug("b1<<2 = " + (b1>>2) ); 175 byte val1 = 176 ((b1 & SIGN) == 0) 177 ? (byte) (b1 >> 2) 178 : (byte) ((b1) >> 2 ^ 0xc0); 179 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 180 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; 181 encodedData[encodedIndex + 2] = PAD; 182 encodedData[encodedIndex + 3] = PAD; 183 } else if (fewerThan24bits == SIXTEENBIT) { 184 185 b1 = binaryData[dataIndex]; 186 b2 = binaryData[dataIndex + 1]; 187 l = (byte) (b2 & 0x0f); 188 k = (byte) (b1 & 0x03); 189 190 byte val1 = 191 ((b1 & SIGN) == 0) 192 ? (byte) (b1 >> 2) 193 : (byte) ((b1) >> 2 ^ 0xc0); 194 byte val2 = 195 ((b2 & SIGN) == 0) 196 ? (byte) (b2 >> 4) 197 : (byte) ((b2) >> 4 ^ 0xf0); 198 199 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 200 encodedData[encodedIndex + 1] = 201 lookUpBase64Alphabet[val2 | (k << 4)]; 202 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; 203 encodedData[encodedIndex + 3] = PAD; 204 } 205 206 return encodedData; 207 } 208 209 public static String decode(String str) { 210 if (str == null) 211 return ""; 212 try { 213 byte[] b = str.getBytes("UTF-8"); 214 return new String(decode(b), "UTF-8"); 215 } catch (UnsupportedEncodingException e) { 216 return ""; 217 } 218 } 219 220 public static byte[] decodeStr2Byte(String str) { 221 if (str == null) 222 return null; 223 try { 224 byte[] b = str.getBytes("UTF-8"); 225 return decode(b); 226 } catch (UnsupportedEncodingException e) { 227 return null; 228 } 229 } 230 231 /** 232 * Decodes Base64 data into octects 233 * 234 * @param binaryData Byte array containing Base64 data 235 * @return Array containing decoded data. 236 */ 237 public static byte[] decode(byte[] base64Data) { 238 // handle the edge case, so we don't have to worry about it later 239 if (base64Data.length == 0) { 240 return new byte[0]; 241 } 242 243 int numberQuadruple = base64Data.length / FOURBYTE; 244 byte decodedData[] = null; 245 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 246 247 // Throw away anything not in base64Data 248 249 int encodedIndex = 0; 250 int dataIndex = 0; 251 { 252 // this sizes the output array properly - rlw 253 int lastData = base64Data.length; 254 // ignore the '=' padding 255 while (base64Data[lastData - 1] == PAD) { 256 if (--lastData == 0) { 257 return new byte[0]; 258 } 259 } 260 decodedData = new byte[lastData - numberQuadruple]; 261 } 262 263 for (int i = 0; i < numberQuadruple; i++) { 264 dataIndex = i * 4; 265 marker0 = base64Data[dataIndex + 2]; 266 marker1 = base64Data[dataIndex + 3]; 267 268 b1 = base64Alphabet[base64Data[dataIndex]]; 269 b2 = base64Alphabet[base64Data[dataIndex + 1]]; 270 271 if (marker0 != PAD && marker1 != PAD) { 272 //No PAD e.g 3cQl 273 b3 = base64Alphabet[marker0]; 274 b4 = base64Alphabet[marker1]; 275 276 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 277 decodedData[encodedIndex + 1] = 278 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 279 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 280 } else if (marker0 == PAD) { 281 //Two PAD e.g. 3c[Pad][Pad] 282 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 283 } else if (marker1 == PAD) { 284 //One PAD e.g. 3cQ[Pad] 285 b3 = base64Alphabet[marker0]; 286 287 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 288 decodedData[encodedIndex + 1] = 289 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 290 } 291 encodedIndex += 3; 292 } 293 return decodedData; 294 } 295 296 public static void main(String[] args) throws UnsupportedEncodingException{ 297 String s = "application=preSign&merchantId=11110000111100192&custName=測試商戶&identityType=01&identityNo=330324198803160199&mobileNo=13738716288&cardType=01&cardNo=6222222222222222&signature=E10ADC3949BA59ABBE56E057F20F883E"; 298 System.out.println("原串: "); 299 System.out.println(s); 300 System.out.println("-------------------------------------------------------------------------------"); 301 String r = encode(s); 302 System.out.println("BASE64編碼後: "); 303 System.out.println(r); 304 System.out.println("-------------------------------------------------------------------------------"); 305 String decode = decode(r); 306 System.out.println("BASE64解碼後:" ); 307 System.out.println(decode); 308 System.out.println("-------------------------------------------------------------------------------"); 309 310 311 } 312 313 }
輸出結果:編碼
1 原串: 2 application=preSign&merchantId=11110000111100192&custName=測試商戶&identityType=01&identityNo=330324198803160199&mobileNo=13738716288&cardType=01&cardNo=6222222222222222&signature=E10ADC3949BA59ABBE56E057F20F883E 3 ------------------------------------------------------------------------------- 4 BASE64編碼後: 5 YXBwbGljYXRpb249cHJlU2lnbiZtZXJjaGFudElkPTExMTEwMDAwMTExMTAwMTkyJmN1c3ROYW1lPea1i+ivleWVhuaItyZpZGVudGl0eVR5cGU9MDEmaWRlbnRpdHlObz0zMzAzMjQxOTg4MDMxNjAxOTkmbW9iaWxlTm89MTM3Mzg3MTYyODgmY2FyZFR5cGU9MDEmY2FyZE5vPTYyMjIyMjIyMjIyMjIyMjImc2lnbmF0dXJlPUUxMEFEQzM5NDlCQTU5QUJCRTU2RTA1N0YyMEY4ODNF 6 ------------------------------------------------------------------------------- 7 BASE64解碼後: 8 application=preSign&merchantId=11110000111100192&custName=測試商戶&identityType=01&identityNo=330324198803160199&mobileNo=13738716288&cardType=01&cardNo=6222222222222222&signature=E10ADC3949BA59ABBE56E057F20F883E 9 -------------------------------------------------------------------------------
提及Base64編碼可能有些奇怪,由於大多數的編碼都是由字符轉化成二進制的過程,而從二進制轉成字符的過程稱爲解碼。而Base64的概念就剛好反了,由二進制轉到字符稱爲編碼,由字符到二進制稱爲解碼。加密
Base64編碼主要用在傳輸、存儲、表示二進制等領域,還能夠用來加密,可是這種加密比較簡單,只是一眼看上去不知道什麼內容罷了,固然也能夠對Base64的字符序列進行定製來進行加密。
Base64編碼是從二進制到字符的過程,像一些中文字符用不一樣的編碼轉爲二進制時,產生的二進制是不同的,因此最終產生的Base64字符也不同。例如"上網"對應utf-8格式的Base64編碼是"5LiK572R",對應GB2312格式的Base64編碼是"yc/N+A=="。