Base64算法并不是真正意义上的加密算法。不过在加密与解密方面经常看到它的身影,比如Base64算法常作为密钥、密文和证书的的一种通用存储编码格式。这是笔者在加解密算法这一系列文章中引入它的原因。
public class JdkBase64 {
public static void main(String[] args) {
String encode = jdkBase64Encode();
jdkBase64Decode(encode);
}
private static String jdkBase64Encode() {
String result = Base64.getEncoder().encodeToString("helloWorld".getBytes(StandardCharsets.UTF_8));
System.out.println(result);
return result;
}
private static void jdkBase64Decode(String src) {
byte[] decode = Base64.getDecoder().decode(src.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(decode, StandardCharsets.UTF_8));
}
}
引入jar包
<dependency>
<groupId>org.bouncycastlegroupId>
<artifactId>bcprov-jdk15onartifactId>
<version>1.67version>
dependency>
代码
public class CastleBase64 {
public static void main(String[] args) {
String encode = encode();
decode(encode);
}
private static String encode() {
String result = Base64.toBase64String("helloWorld".getBytes(StandardCharsets.UTF_8));
System.out.println(result);
return result;
}
private static void decode(String src) {
byte[] decode = Base64.decode(src.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(decode, StandardCharsets.UTF_8));
}
}
引入jar包
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
<version>1.14version>
dependency>
代码
public class CodecBase64 {
public static void main(String[] args) {
String encodeStr = encode();
System.out.println(encodeStr);
decode(encodeStr);
}
private static String encode() {
byte[] result = Base64
.encodeBase64("helloWorld".getBytes(StandardCharsets.UTF_8));
return new String(result, StandardCharsets.UTF_8);
}
private static void decode(String encodeStr) {
byte[] decode = Base64.decodeBase64(encodeStr);
System.out.println(new String(decode, StandardCharsets.UTF_8));
}
}
Base64算法是一种基于64个字符的编码算法,根据RFC2045的定义:
The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.
经过Base64编码后的数据会比原来数据略长,为原来的4/3倍。编码后的字符串的字符数是以4位单位的整数倍。
在RFC 2045文件中给出的字符映射表如下:
这张字符映射表中,Value指的是十进制编码,Encoding指的是字符,共映射了64个字符,这也是该算法命名的由来。映射表的最后一个字符是等号,是用来补位的,看到有一串字符以等号结尾的,基本上会联想到Base64
Base64算法主要是将给定的字符以字符编码(如ASCII码,UTF-8)对应的十进制为基准,做编码操作:
步骤 | 结果 |
---|---|
原文字符 | B |
ASCII码 | 66 |
8位二进制码 | 01000010 |
4-6二进制码 | 010000 100000 |
4-8二进制码 | 00010000 00100000 |
十进制码 | 16 32 |
字符表映射码 | Q g |
进行补位 | Qg== |
当原文的二进制码长度不足24位,最终转换成十进制码时也不足4项,就需要用等号补位
ASCII码可以表示十进制范围为0~127的字符,对应的二进制范围是0000 0000 ~ 0111 1111。ASCII码包括阿拉伯数字、大小写英文字母和一些控制符,没有包含双字节编码的字符如中文字符。UTF-8编码使用3个字节表示一个汉字。
下面对中文进行推导
步骤 | 结果 |
---|---|
原文字符 | 好 |
UTF-8码字节 | -27 -91 -67 |
8位二进制码 | 11100101 10100101 10111101 |
4-6二进制码 | 111001 011010 010110 111101 |
4-8二进制码 | 00111001 00011010 00010110 00111101 |
十进制码 | 57 26 22 61 |
字符表映射码 | 5aW9 |
按照以上的步骤,可以使用以下工具类,找到转换后的十进制码,最后在对照Base64编码表,即可得到映射码。最后结果可以以上面提到的实现方式进行比较。
public class BinaryUtil {
public static void main(String[] args) {
byte[] bytes = utfByte("好"); // 根据utf-8编码字节
for (byte eachByte : bytes) {
String binary = byteToBinary(eachByte); // 转换成二进制
System.out.println(eachByte + ":" + binary);
}
System.out.println(binaryToDecimal("00011010")); // 二进制装换成十进制
}
public static byte[] utfByte(String msg) {
return msg.getBytes(StandardCharsets.UTF_8);
}
public static String byteToBinary(byte src) {
return Integer.toBinaryString((src & 0xFF) + 0x100).substring(1);
}
public static Map<Byte, String> stringToBinary(String src) {
Map<Byte, String> result = new HashMap<Byte, String>();
for (byte each : src.getBytes()) {
result.put(each, byteToBinary(each));
}
return result;
}
public static int binaryToDecimal(String src) {
return Integer.parseInt(src, 2);
}
}
Base64加密解密经常用到。不过其并不是真正意义上的加密解密算法。通过上面的原理推导,知道一串Base64编码的字符串完成能够找到其原码。所以,对于实际需要传输个人数据和敏感信息,Base64不适用此场景。