目录
Base64算法的由来
Base64算法的原理
Base64编码与urlEncode编码的区别
Base64算法最早应用于解决电子邮件传输问题,在早期,电子邮件只支持ASCII码字符。如果要传输一封带有非ASCII码字符的电子邮件,当它经过部分网关时就可能出现问题,这个网关可能会对非ASCII码字符的二进制位进行调整,即将这个非ASCII码的8位二进制码最高位置设置为0,此时用户收到的这个邮件就会是一封乱码的了。基于这个原因产生了Base64算法。
Base64是一种基于64个字符的编码算法。经过Base编码后的数据会比原始数据略长,为原来的4/3。经过Base64编码的字符串的字符数是以4为单位的整数倍。
RFC2045规定,在电子邮件中,每行为76个字符,每行末尾添加一个回车换行符(“\r\n”),无论每行是否够76个字符,都要加一个回车换行符。但实际情况中往往要忽略这一点。
我经常听到有人说Base64加密,听着十分变扭。准确地说,Base64是一种编码。
这张字符映射表中,Value指的是十进制编码,Encoding指的是字符,共映射了64个字符,这也是Base64算法命名的来源。映射表的最后一个字符是等号,它是用来补位的。
为了能在HTTP请求中以GET方式传递二进制数,由Base64算法衍生出了Url Base64算法。Url Base64主要是替换了Base64字符映射表中的第62、63个字符,也就是将”+”和”/”符号用”-“和”_”代替。至于”=”在Bouncy Castle提供者使用的是”.”代替,而在Commons Codec里则是完全杜绝使用补位符。
Base64算法主要是将给定的字符以及字符编码(如ASCII码、UTF-8码)对应的十进制数为基准,做编码操作:
将给定的字符串以字符为单位,转换成对应的字符编码(如ASCII码)
将字符编码转换成二进制
将二进制码进行分组转换操作,每3个8位二进制码为一组,转换为每4个6位二进制码为一组(不足6位时低位补0)。这是一个分组变化的过程,3个8位二进制码和4个6为二进制码的长度都是24位
将获得的4-6二进制码组进行补位,向6位二进制码高位补2个0,组成4个8位二进制码
将获得的4-8二进制码组转换为十进制码
将获得的十进制码转换成Base64字符表中对应的字符
例子1:假设场景,我们需要对"A"进行Base64编码,操作如下:
字符============================A
ASCII编码======================65
二进制码=======================01000001
4-6二进制码====================010000 010000(不足6位,低位补0)
4-8二进制码====================00010000 00010000
十进制码======================16 16
字符映射表====================Q Q = =
最终获得是”QQ==”出现2个补位的原因,是我们要满足,Base64编码出来的串必须是4的整数倍,不够就补。此处,源二进制码为01000001不足24位,导致4-8二进制码组不足4个。我们这里可以通过一个简单的方法判断是否需要补位:
余数=原文字节数 MOD 3余数=0,不需要补位
余数=1,补2个等号
余数=2,补1个等号
例子2:解决非ASCII码字符编码的传输问题
字符 =========================================== 密
UTF-8码 -27 -81 -122
二进制码 11100101 10101111 10000110
4-6二进制码 111001 011010 111110 000110
4-8二进制码 00111001 00011010 00111110 00000110
十进制码 57 26 62 6
字符映射 5 a + G
字符串"密"经过Base64加密得到字符串"5a+G",当然,使用GBK编码的"密"就不是这个结果了。
Base64编码与urlEncode编码的区别
UrlEncode:
- `POST`请求中URLEncode和URLDecode用于完成普通字符串和
`application/x-www-from-urlencoded MIME`字符串之间的相互转化。
- `GET`请求中字符串数据以url的形式传递给web服务器时,字符串中是不允许出现空格和特殊字符的。
UrlEncode的过程:
URL_ENCODE的过程就是把URL作为字符按照某种编码方式(GBK, UTF-8等)编码成二进制的字节码,然后每个字节用一个包含3个字符的字符串 “%xy” 表示,其中xy为该字节的两位十六进制表示形式。
URL 只能使用 ASCII 字符集来通过因特网进行发送。除了 -_. 等规定之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)主要用于编码 URL 和安全传输URL 。
RFC 1738规定:只有字母和数字[0-9a-zA-Z]、一些特殊符号$-_.+!*'(),[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。
Base64:
- 电子邮件传输:可以进行简单"加密"且防乱码
- 网络数据传输:不论是通过`HTTP`的`GET`方式以URL参数传递参数,还是通过`POST`方式以数据体传输数据,都能发现Base64编码藏匿其中
- 密钥存储:将密钥从二进制表现形式转换成Base64,这样可读性变得更高
- 数字证书存储:很多数字证书以Base64方式存储和传输
代码实例
public static void main(String[] args) throws Exception{
String s = "高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+高堂明镜悲白发,朝如青丝暮成雪+";
System.out.println("遵循RFC2048:"+ new String(Base64.encodeBase64(s.getBytes("UTF-8"),true)));
System.out.println("=================================================================================");
System.out.println("不遵循RFC2048:"+Base64.encodeBase64String(s.getBytes("UTF-8")));
}
运行结果: