突然想起来过去在给长春公安局的系统中短暂使用过base64图片,以过去了解的知识来看,java的base64加密不属于基础包的内容,需要额外引入rt.jar,所以今儿就看他了。
主要参考了两篇关于base64编码的原理及实现 和 Base64加密算法源码(java版)
base64编码,是可恢复的一种编码形式,编码过程如下
1. 将输入的byte数组进行分组,每3个byte一组
2. 将3个byte分组,3byte共24个bit,分成4组,每组6bit,高位用00补齐,生成4个新的byte
3. 将4个byte根据映射表对照生成新的byte数组
4. 重复1到3,如果1过程不足3个,在生成的byte数组末尾添加1到2个‘=’补齐
映射表如下
<span style="white-space:pre"> </span>encodingTable = { (byte) 'A', (byte) 'B',
(byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
(byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
(byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q',
(byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V',
(byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a',
(byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
(byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k',
(byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p',
(byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
(byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
(byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
(byte) '+', (byte) '/' };
根据编码过程,有编码的实现
/**
*
* @param data
* 输入byte数组
* @return 输出加密后的byte数组
*/
public static byte[] encode(byte[] data) {
if (null == data)
return null;
int mod = data.length % 3;
byte[] result;
if (mod == 0) {
result = new byte[4 * (data.length / 3)];
} else {
result = new byte[4 * (data.length / 3 + 1)];
}
int dataLength = (data.length - mod);
int byte1;
int byte2;
int byte3;
for (int i = 0, j = 0; i < dataLength; i += 3, j += 4) {
byte1 = data[i] & 0xff;
byte2 = data[i + 1] & 0xff;
byte3 = data[i + 2] & 0xff;
result[j] = encodingTable[(byte1 >> 2) & 0x3f];
result[j + 1] = encodingTable[((byte1 << 4) | (byte2 >> 4)) & 0x3f];
result[j + 2] = encodingTable[((byte2 << 2) | (byte3 >> 6)) & 0x3f];
result[j + 3] = encodingTable[byte3 & 0x3f];
}
int last1, last2;
switch (mod) {
// 不需要补全=
case 0:
break;
// 需要补全2个=
case 1:
last1 = data[data.length - 1];
result[result.length - 4] = encodingTable[(last1 >> 2) & 0x3f];
result[result.length - 3] = encodingTable[(last1 << 4) & 0x3f];
result[result.length - 2] = (byte) '=';
result[result.length - 1] = (byte) '=';
break;
// 需要补全1个=
case 2:
last2 = data[data.length - 2];
last1 = data[data.length - 1];
result[result.length - 4] = encodingTable[(last2 >> 2) & 0x3f];
result[result.length - 3] = encodingTable[(last2 << 4 | last1 >> 4) & 0x3f];
result[result.length - 2] = encodingTable[(last1 << 2) & 0x3f];
result[result.length - 1] = (byte) '=';
break;
}
return result;
}
// 解密映射表
private static byte[] decodeTable() {
byte[] decodingTable;
decodingTable = new byte[128];
for (int i = 0; i < 128; i++) {
decodingTable[i] = (byte) -1;
}
for (int i = 'A'; i <= 'Z'; i++) {
decodingTable[i] = (byte) (i - 'A');
}
for (int i = 'a'; i <= 'z'; i++) {
decodingTable[i] = (byte) (i - 'a' + 26);
}
for (int i = '0'; i <= '9'; i++) {
decodingTable[i] = (byte) (i - '0' + 52);
}
decodingTable['+'] = 62;
decodingTable['/'] = 63;
return decodingTable;
}
生成的映射表如下
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 62 -1 -1 -1 63 52 53
54 55 56 57 58 59 60 61 -1 -1
-1 -1 -1 -1 -1 0 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 -1 -1 -1 -1 -1 -1 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 -1 -1 -1 -1 -1
解码过程代码如下
/**
*
* @param str
* 需要解码的byte数组
* @return 解码后的数组
*/
public static byte[] decode(byte[] str) {
if (null != str && str.length % 4 != 0)
return null;
byte[] decodetable = decodeTable();
int length = str.length;
byte[] result = new byte[length * 3 / 4];
byte byte1, byte2, byte3, byte4;
for (int i = 0, j = 0; i < length - 4; i += 4, j += 3) {
byte1 = decodetable[str[i]];
byte2 = decodetable[str[i + 1]];
byte3 = decodetable[str[i + 2]];
byte4 = decodetable[str[i + 3]];
result[j] = (byte) (byte1 << 2 | byte2 >> 4);
result[j + 1] = (byte) (byte2 << 4 | byte3 >> 2);
result[j + 2] = (byte) (byte3 << 6 | byte4);
}
// 存在2个=
if (str[length - 2] == '=') {
byte1 = decodetable[str[length - 4]];
byte2 = decodetable[str[length - 3]];
result[result.length - 1] = (byte) (byte1 << 2 | byte2 >> 4);
}
// 存在1个=
else if (str[length - 1] == '=') {
byte1 = decodetable[str[length - 4]];
byte2 = decodetable[str[length - 3]];
byte3 = decodetable[str[length - 2]];
result[result.length - 2] = (byte) (byte1 << 2 | byte2 >> 4);
result[result.length - 1] = (byte) (byte2 << 4 | byte3 >> 2);
}
// 不存在=
else {
byte1 = decodetable[str[length - 4]];
byte2 = decodetable[str[length - 3]];
byte3 = decodetable[str[length - 2]];
byte4 = decodetable[str[length - 1]];
result[result.length - 3] = (byte) (byte1 << 2 | byte2 >> 4);
result[result.length - 2] = (byte) (byte2 << 4 | byte3 >> 2);
result[result.length - 1] = (byte) (byte3 << 6 | byte4);
}
return result;
}
测试
public static void main(String[] args) {
String str = "hello base64!";
// 加密
byte[] base64 = encode(str.getBytes());
for (int i = 0; i < base64.length; i++) {
System.out.print((char) base64[i]);
}
System.out.println();
// 解密
byte[] decode = decode(base64);
for (int i = 0; i < decode.length; i++) {
System.out.print((char) decode[i]);
}
System.out.println();
}
aGVsbG8gYmFzZTY0IQ==
hello base64!