天天看点

BASE64的介绍及用Java语言编写代码实现

作者:编程实践
BASE64的介绍及用Java语言编写代码实现

1、引言

说到加密解密,很多书籍都会把BASE64扯进来,并且和MD5、SHA放在一起讲解,作为不可逆加密方案的一部分。

但这些书籍,在描述BASE64时,又会特别指出,BASE64并不是不可逆加密方案,是可逆的,并且根本算不上加密。

本质上来说,BASE64只是将二进制数据(包括字符数据),换了一种编码方式,变成了人不可以直接阅读的文本。

2、BASE64的定义

BASE64是在RFC2045中定义的,大家在百度中输入“RFC2045”,即可找到该文档的全文。

RFC2045用于定义MIME(多用途因特网邮件扩展协议),定义了消息体的格式。该文档的6.8节(Base64 Content-Transfer-Encoding)详细描述了BASE64编码的规则。

BASE64的编码的详细描述如下:

(1)可以对任意的字节序列进行编码;

(2)编码的结果比源码长33%;

(3)BASE64使用了65个ASCII字符来表示编码结果;

(4)BASE64中的64个字符代表6bit的值;

(5)BASE64除了表示值的64个字符外,还有一个等号字符=,有特殊含义;

(6)BASE64将24bit,也就是3个字节,变成4个字符;

(7)BASE64将原始数据当成大端格式的字节序列,即第一个bit是高位,对应的英语表示是most-significant-bit first;

(8)6bit值与BASE64的字符映射关系如下:

BASE64的介绍及用Java语言编写代码实现

(9)BASE64编码结果中的回车、换行以及其他字符,必须被忽略;

(10)输入的字节数组,按照每3字节变成生成4个字符,如果最后不足3字节,则没法凑足成6bit的序列,不足的部分通过补充0来满足;

(11)如果输入的字节数组,最后只剩一个字节未编码,则只能凑足两个6bit,输出的结果带两个等号==;

(12)如果输入的字节数组,最后只剩两个字节未编码,则只能凑足三个6bit,输出的结果带一个等号=。

这样流水账式的描述,虽然挺繁琐,却是程序员最习惯的。

3、手工计算BASE64编码值

如果我们对三字节序列0x00 0x00 0x00进行BASE64编码,相当于对四个6bit值 0,0,0,0进行映射转换,结果自然是AAAA;

如果我们对两字节序列0x00 0x00进行BASE64编码,相当于对补零之后的三个6bit值0,0,0进行映射转换,结果是AAA=;

如果我们对单字节0x00进行BASE64编码,相当于对补零之后的两个6bit值0,0进行映射转换,结果是AA==;

如果对于非零的值,例如对三字节序列0x01 0x01 0x01进行转换,以字节序列的视角来看,是这样的:

BASE64的介绍及用Java语言编写代码实现

如果以6bit序列的视角来看,则是这样的:

BASE64的介绍及用Java语言编写代码实现

相当于4个6bit的值 0,16,4,1,进行映射转换,结果就是AQEB。

4、使用JDK的BASE64编码功能

JDK提供了多个关于BASE64编码的类,这里使用BASE64Encoder类来完成。代码如下:

package com.flying.base;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import sun.misc.BASE64Encoder;
@SpringBootApplication
public class BaseApplication {
public static void main(String[] args) {
SpringApplication.run(BaseApplication.class, args);
BASE64Encoder base64Encoder = new BASE64Encoder();
byte[] bytes;
bytes = new byte[]{0, 0, 0};
System.out.println("BASE64 of {0, 0, 0} is: " + base64Encoder.encode(bytes));
bytes = new byte[]{0, 0};
System.out.println("BASE64 of {0, 0} is: " + base64Encoder.encode(bytes));
bytes = new byte[]{0};
System.out.println("BASE64 of {0} is: " + base64Encoder.encode(bytes));
bytes = new byte[]{1, 1, 1};
System.out.println("BASE64 of {1, 1, 1} is: " + base64Encoder.encode(bytes));
}
}           

程序的运行结果为:

BASE64的介绍及用Java语言编写代码实现

可以看到,程序的运行结果和手工计算的结果相同。

5、自己写代码实现简易的BASE64编码功能

BASE64编码的规则很简单,我们完全可以自己实现一个简易版本的,这是我临时编写的代码,大家将就着看一下:

package com.flying.base;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BaseApplication {
public static void main(String[] args) {
SpringApplication.run(BaseApplication.class, args);
byte[] bytes;
bytes = new byte[]{0, 0, 0};
System.out.println("Self BASE64 of {0, 0, 0} is: " + base64Encode(bytes));
bytes = new byte[]{0, 0};
System.out.println("Self BASE64 of {0, 0} is: " + base64Encode(bytes));
bytes = new byte[]{0};
System.out.println("Self BASE64 of {0} is: " + base64Encode(bytes));
bytes = new byte[]{1, 1, 1};
System.out.println("Self BASE64 of {1, 1, 1} is: " + base64Encode(bytes));
}
private static char[] base64Characters ={
'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', '+', '/'
};
static String base64Encode(byte[] bytes){
if (bytes == null || bytes.length == 0){
return "";
}
int index1, index2, index3, index4;
StringBuilder stringBuilder = new StringBuilder();
int timesOfThree = bytes.length / 3;
for (int i=0; i<timesOfThree; i++){
index1 = bytes[i*3] >> 2;
index1 = index1 & 0x3F;
index2 = bytes[i*3] & 0x03;
index2 = index2 << 4;
index2 = index2 | ((bytes[i*3+1] & 0xF0) >> 4);
index2 = index2 & 0x3F;
index3 = bytes[i*3+1] & 0x0F;
index3 = index3 << 2;
index3 = index3 | ((bytes[i*3+2] & 0xC0) >> 6);
index3 = index3 & 0x3F;
index4 = bytes[i*3+2] & 0x3F;
stringBuilder.append(base64Characters[index1]).append(base64Characters[index2]).append(base64Characters[index3]).append(base64Characters[index4]);
}
int remainPos = bytes.length / 3;
remainPos = remainPos * 3;
switch (bytes.length % 3){
case 1:
index1 = bytes[remainPos*3] >> 2;
index1 = index1 & 0x3F;
index2 = bytes[remainPos*3] & 0x03;
index2 = index2 << 4;
index2 = index2 & 0x3F;
stringBuilder.append(base64Characters[index1]).append(base64Characters[index2]).append('=').append('=');
break;
case 2:
index1 = bytes[remainPos*3] >> 2;
index1 = index1 & 0x3F;
index2 = bytes[remainPos*3] & 0x03;
index2 = index2 << 4;
index2 = index2 | ((bytes[remainPos*3+1] & 0xF0) >> 4);
index2 = index2 & 0x3F;
index3 = bytes[remainPos*3+1] & 0x0F;
index3 = index3 << 2;
index3 = index3 & 0x3F;
stringBuilder.append(base64Characters[index1]).append(base64Characters[index2]).append(base64Characters[index3]).append('=');
break;
default:
break;
}
return stringBuilder.toString();
}
}           

程序的运行结果如下:

BASE64的介绍及用Java语言编写代码实现

上面的示例代码,只进行了BASE64的编码,如果你感兴趣,可以尝试编写BASE64解码的程序。

继续阅读