0%

Base64 Coding

Base64是网络上一种常用的编码技术,常用于数据传输,但不是加密技术。

Base64其核心在于使用6个位的Base64字符来表示8个位的ASCII码,也就是每4个Base64字符表示3个ASCII字符。

Base64的每个字符只有6个位,因此最多可以表示$2^6=64$个字符.

有一张对应表。

字符 字符 字符 字符 字符 字符 字符 字符
A 0 B 1 C 2 D 3 E 4 F 5 G 6 H 7
I 8 J 9 K 10 L 11 M 12 N 13 O 14 P 15
Q 16 R 17 S 18 T 19 U 20 V 21 W 22 X 23
Y 24 Z 25 a 26 b 27 c 28 d 29 e 30 f 31
g 32 h 33 i 34 j 35 k 36 l 37 m 38 n 39
o 40 p 41 q 42 r 43 s 44 t 45 u 46 v 47
w 48 x 49 y 50 z 51 0 52 1 53 2 54 3 55
4 56 5 57 6 58 7 59 8 60 9 61 + 62 / 63

将ASCII转换成Base64的流程是这样的

e.g. 将ASCII的字符串”ABC”转成Base64

A B C
01000001 01000010 01000011

每六位转成Base64的编码,去查表

010000 010100 001001 000011
Q U J D

Base64编码后的字符串”ABC”即”QUJD”

可以看出,每三个ASCII字符转成四个Base64字符,如果不满3个的情况下,是这样的

e.g.将ASCII的字符串”AB”转成Base64

A B
01000001 01000010
010000 010100 001000
Q U I

注意到AB两个ASCII码只有16位,三个Base64编码18位,因此最后两位补0

不满四个字符,在后面补充”=”

Base64编码后的字符串”ABC”即”QUI=”

另附Java实现Base64的编码与解码

编码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Base64Encoder {
private static char[] base64Map = { '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 String encoder(String plainText) {
if (plainText == null || plainText.length() <= 0) {
return null;
}
StringBuilder ciptext = new StringBuilder();
char[] plain = plainText.toCharArray();
int equalsNum = 0;

equalsNum = (3 - (plain.length % 3)) % 3;

for (int i = 0; i < plain.length; i += 3) {
int temp;
if (i + 2 < plain.length) {
temp = (((int) plain[i]) << 16) + (((int) plain[i + 1]) << 8) + ((int) plain[i + 2]);
ciptext.append(base64Map[(temp & (((1 << 6) - 1) << 18)) >>> 18]);
ciptext.append(base64Map[(temp & (((1 << 6) - 1) << 12)) >>> 12]);
} else if (i + 1 < plain.length) {
temp = (((int) plain[i]) << 8) + ((int) plain[i + 1]);
temp <<= 2;
ciptext.append(base64Map[(temp & (((1 << 6) - 1) << 12)) >>> 12]);
} else {
temp = ((int) plain[i]) << 8;
temp <<= 4;
}
ciptext.append(base64Map[(temp & (((1 << 6) - 1) << 6)) >>> 6]);
ciptext.append(base64Map[temp & ((1 << 6) - 1)]);
}

ciptext.append(equalsNum == 0 ? "" : (equalsNum == 1 ? "=" : "=="));

return ciptext.toString();
}
}

解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Base64Decoder {
private static int[] base64Map = new int[128];

static {
for (int i = 0; i < 26; ++i) {
base64Map[i + 'A'] = i;
}
for (int i = 0; i < 26; ++i) {
base64Map[i + 'a'] = i + 26;
}
for (int i = 0; i < 10; ++i) {
base64Map[i + '0'] = i + 52;
}
base64Map['+'] = 62;
base64Map['/'] = 63;
}

public String decoder(String ciptext) {
if (ciptext == null || ciptext.length() <= 0 || ciptext.length() % 4 != 0) {
return null;
}

StringBuilder plaintext = new StringBuilder();

if (ciptext.endsWith("==")) {
ciptext = ciptext.substring(0, ciptext.length() - 2);
} else if (ciptext.endsWith("=")) {
ciptext = ciptext.substring(0, ciptext.length() - 1);
}

char[] cip = ciptext.toCharArray();

for (int i = 0; i < cip.length; i += 4) {
int temp;
if (i + 3 < cip.length) {
temp = (base64Map[cip[i]] << 18) + (base64Map[cip[i + 1]] << 12) + (base64Map[cip[i + 2]] << 6)
+ (base64Map[cip[i + 3]]);
String str = "";
str += (char) (temp & ((1 << 8) - 1));
temp >>>= 8;
str = (char) (temp & ((1 << 8) - 1)) + str;
temp >>>= 8;
str = (char) (temp & ((1 << 8) - 1)) + str;
temp >>>= 8;
plaintext.append(str);
} else if (i + 2 < cip.length) {
temp = (base64Map[cip[i]] << 10) + (base64Map[cip[i + 1]] << 4) + (base64Map[cip[i + 2]] >>> 2);
String str = "";
str += (char) (temp & ((1 << 8) - 1));
temp >>>= 8;
str = (char) (temp & ((1 << 8) - 1)) + str;
plaintext.append(str);
} else {
temp = (base64Map[cip[i]] << 2) + (base64Map[cip[i + 1]] >>> 4);
plaintext.append((char) temp);
}
}
return plaintext.toString();
}
}