Base64加密转换原理与代码实现

一、Base64实现转换原理

  它是用64个可打印字符表示二进制所有数据方法。由于2的6次方等于64,所以可以用每6个位元(bit)为一个单元,对应某个可打印字符。我们知道三个字节(byte)有24个位元,就可以刚好对应于4个Base64单元,即3个字节需要用4个Base64的可打印字符来表示。

Base64加密转换原理与代码实现

  · 可打印符号:

  在Base64中的可打印字符包括字母A-Z、a-z、数字0-9 ,这样共有62个字符,此外两个可打印符号在不同的系统中一般有所不同。但是,我们经常所说的Base64另外2个字符是:“+/”。这64个字符,所对应表如下:

编号 字符   编号 字符   编号 字符   编号 字符
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 /

  

  仔细思考一下,你会很快发现,一个问题,就是每次转换的字节数不一定就是24的整数倍,会出现有多余不足六位的情况,在base64中处理的方法是加零凑够六位,但是这样一来在解码的时候就会出现多余的位  这该怎么办呢? base64想到了一个很好的解决办法。这个办法就是在 base64凑零的同时,还要满足凑出来的位数是8的倍数,不然就加一个或者两个特殊的六位  =  符号。为什么是一个或者两个=符号呢? 因为多个8位转为6位 只会出现 剩余 2位,4位的情况,剩余2位 只需要一个 表示六位的 =  便可变为8的整数;而剩余4位 需要两个表示6位的 = 便可以变成16 是8的整数。然后在解密的时候不解析 =即可。

之所以位的总数需要凑成8的倍数,是因为base64主要用于加密后的数据传送,而在传送机制中都认为传送的最小单位是按照字节算的,所以不能出现不是位总数不是8的倍数的情况,在接收到数据后,按顺序将6位的base64直接按照顺序解密成字节就完成解密了。

· 转换过程:

    ① 将三个byte(字节)的数据,先后放入一个24bit(位)的缓冲区中,先来的byte占高位。数据不足 3 byte的话,于缓冲区中剩下的bit用0补足。

    ② 然后,每次取出6个bit,按照其值选择 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。

    ③    如果最后剩下两个输入数据,在编码结果后加1个“=”;

      如果最后剩下一个输入数据,编码结果后加2个“=”;

      如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

   编码后的数据比原始数据略长,为原来的4/3。

文本 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

M的Ascii码是77,前六位对应值为19,对应base64字符是T,如此类推。其它字符编码就可以自动转换得到!我们看看另外不是刚好是3个字节的情况!

文本(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  =

二、Base64转换代码实现

 public class Base64Util {
private static final char last2byte = (char) Integer.parseInt("00000011", 2);
private static final char last4byte = (char) Integer.parseInt("00001111", 2);
private static final char last6byte = (char) Integer.parseInt("00111111", 2);
private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
private static final char[] encodeTable = new char[]
{
'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', '+', '/'
}; public Base64Util() {
} public static String encode(byte[] from) {
StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3);
int num = 0;
char currentByte = 0; int i;
for (i = 0; i < from.length; ++i) {
for (num %= 8; num < 8; num += 6) {
switch (num) {
case 0:
currentByte = (char) (from[i] & lead6byte);
currentByte = (char) (currentByte >>> 2);
case 1:
case 3:
case 5:
default:
break;
case 2:
currentByte = (char) (from[i] & last6byte);
break;
case 4:
currentByte = (char) (from[i] & last4byte);
currentByte = (char) (currentByte << 2);
if (i + 1 < from.length) {
currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6);
}
break;
case 6:
currentByte = (char) (from[i] & last2byte);
currentByte = (char) (currentByte << 4);
if (i + 1 < from.length) {
currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4);
}
} to.append(encodeTable[currentByte]);
}
} if (to.length() % 4 != 0) {
for (i = 4 - to.length() % 4; i > 0; --i) {
to.append("=");
}
} return to.toString();
}
}
上一篇:JavaScript实现判断图片是否加载完成的3种方法整理


下一篇:如何直接在github网站上更新你fork的repo?