共计 4402 个字符,预计需要花费 12 分钟才能阅读完成。
hi,大家好,我是开发者 FTD。置信很多同学在工作中,常常会用到 Base64 编码,那大家晓得为什么会有 Base64 编码吗?咱们为什么要应用它呢,它又是怎么实现的呢?上面就让咱们来一起深刻探索一下 Base64 编码吧。
Base 家族
在开始之前,咱们先给大家介绍一下 Base 家族。尽管咱们在工作中应用最多的是 Base64,然而 Base 家族可不止是只有 Base64,除了 Base64 之外,Base 家族还有 Base32 和 Base16。
咱们都晓得 ASCII 编码,ASCII 编码是用 256(2 的 8 次方)个字符,对二进制数据进行编码的形式,同样的
- Base64 编码是用 64(2 的 6 次方)个字符,对二进制数据进行编码的形式
- Base32 编码是用 32(2 的 5 次方)个字符,对二进制数据进行编码的形式
- Base16 编码是用 16(2 的 4 次方)个字符,对二进制数据进行编码的形式
那 Base 家族有这么多编码模式,为什么偏偏应用 Base64 呢?
- Base64 编码是用 64(2 的 6 次方)个特定的 ASCII 字符来示意 256(2 的 8 次方)个 ASCII 字符,也就是说三个 ASCII 字符通过 Base64 编码后变为四个的 ASCII 字符显示(公约数为 24),编码后数据长度比原来减少 1 /3,有余 3n 用“=”补足。
- Base32 编码就是用 32(2 的 5 次方)个特定的 ASCII 字符来示意 256(2 的 8 次方)个 ASCII 码,也就是说五个 ASCII 字符通过 Base32 编码后会变为八个 ASCII 字符显示(公约数为 40),编码后数据长度比原来减少 3 /5,有余 8n 用“=”补足。
- Base16 编码就是用 16(2 的 4 次方)个特定的 ASCII 字符示意 256(2 的 8 次方)个 ASCII 字符,也就是说一个 ASCII 字符通过 Base16 编码后会变为两个 ASCII 字符显示,编码后数据长度比原来增加一倍,有余 2n 用“=”补足。
从下面能够看出 Base64 编码后,长度减少是起码的,这也是咱们选用 Base64 的一个重要起因。
Base64 简介
Base64 顾名思义,就是基于 64 个可打印字符来示意二进制数据的一种办法,留神它并不是一种加密算法。对于 64 个打印字符,咱们只须要 6 个二进制位就能够齐全示意了。那么咱们如何利用 8 个二进制位来示意只须要 6 个二进制位就能够齐全示意的可打印字符呢?因为 2 的 6 次方等于 64,所以咱们能够将每 6 个位元为一个单元,对应某个可打印字符。三个字节有 24 个位元,对应于 4 个 Base64 单元,即 3 个字节须要用 4 个可打印字符来示意。
Base64 是从二进制数据到字符的过程。所以计算机中所有的内容,包含文本、图片、音频、视频等等都能够应用 Base64 编码来示意。
Base64 编码原理
Base64 编码就是应用 64 个字符作为一个根本字符集:
小写字母 a -z、大写字母 A -Z、数字 0 -9、符号 ”+”、”/”(再加上作为垫字的 ”=”,实际上是 65 个字符)
而后,所有其余符号都依据肯定规定转换成这个字符集中的字符。
具体来说,Base64 编码的转换形式能够分为以下四步:
- 第一步,将每三个字节作为一组,一共是 24 个二进制位
- 第二步,将这 24 个二进制位分为四组,每个组有 6 个二进制位
- 第三步,在每组后面加两个 00,扩大成 32 个二进制位,即四个字节
- 第四步,依据下表,失去扩大后的每个字节的对应符号,这就是 Base64 的编码值
Base64 编码的字符索引表如下所示:
数值 | 字符 | 数值 | 字符 | 数值 | 字符 | 数值 | 字符 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |
有了这个字符索引表,咱们就能够把任意的二进制转换成 Base64 的编码了,上面咱们通过几个例子,给大家展现一下转换的过程。
1,假如当初有字符串 FTD 须要转换成 base64 的编码格局
- 第一步:“F”、“T”、”D” 字符对应的 ASCII 码值别离为 70,84,68,对应的二进制值是 01000110、01010100、01000100。如图第二三行所示,由此组成一个 24 位的二进制字符串。
- 第二步:将 24 位二进制依照每 6 位二进制位一组分成四组。
- 第三步:在下面每一组后面补两个 0,扩大成 32 个二进制位,此时变为四个字节:00010001、00100101、00010001、00000100。别离对应的值(Base64 编码索引)为:17、37、17、4。
- 第四步:用下面的值在 Base64 字符索引表中进行查找,别离对应:R、I、R、E。
因而字符串“FTD”通过 Base64 编码之后就变为:RIRE。
2,下面的例子中的字符正好是三个字节,如果字节数有余三个时该如何解决呢?上面咱们以 F 和 FT 别离举例说明如下:
如上表所示,因为字符 F 的二进制为 01000110,依照每 6 位进行分组,此时只能分成一组,第二组短少 4 位,如果位数有余时,用 0 补齐;第三组和第四组齐全没有数据,则用 = 补上。因而,字符 F 通过 Base64 编码后失去的数值为Rg==。
3,上面咱们再看一下如果只有两个字符的状况:
如上表所示,这个也属于位数有余,须要补位的状况。第一组和第二组依照失常的分组计算,第三组因为有余位数,最初两位补 0,第四组齐全没有数据,用 = 补上。因而,字符 FT 通过 Base64 编码后失去的数值为RlQ=。
对于中文的 Base64 编码
大家都晓得中文编码有很多种,例如GB2312、GBK、GB18030,不同的汉字应用不同的编码格局进行编码后,它的二进制是不同的,所以在进行 Base64 编码后,他们的 Base64 编码的值也是不同的。这就要求咱们在解码的时候须要留神原文的字符集格局,肯定要保持一致能力正确解码。
例如:
中文“【我是开发者 FTD】公众号”UTF-8 格局的 Base64 编码后的值是:44CQ5oiR5piv5byA5Y+R6ICFRlRE44CR5YWs5LyX5Y+3
中文“【我是开发者 FTD】公众号”GB2312 格局的 Base64 编码后的值是:ob7O0srHv6q3otXfRlREob+5q9bausU=
Base64 是加密算法吗?
Base64 次要不是用来加密的,它次要的用处是把一些二进制数转成一般字符用于网络传输,这是因为一些二进制字符在传输协定中属于控制字符,不能间接在网络上传输。另外,还有一些零碎中只能应用 ASCII 字符。Base64 编码就是用来将非 ASCII 字符的数据转换成 ASCII 字符的一种办法。Base64 并不是平安畛域下的加密解密算法,尽管有时候也会常常看到所谓的 Base64 加密解密算法。其实 Base64 只能算是一个编码算法,对数据内容进行编码来适宜网络传输。尽管 Base64 编码过后原文也变成无奈间接了解的字符格局,然而这种编码方式比拟高级,很简略,很容易就能够被还原成原文,所以如果有比拟重要的信息须要加密,肯定要应用咱们之前文章中介绍的那些加密算法进行数据的平安爱护。
Base64 编码实现
Java 语言中有多个库实现了 Base64 编码,不论哪一个库,最终的后果都是一样的。
JDK 提供的 Base64 编码实现:
public static String encode(String data) {return Base64.getEncoder().encodeToString(data.getBytes());
}
public static String decode(String base64Data) {return new String(Base64.getDecoder().decode(base64Data));
}
Bouncy Castle 提供的 Base64 编码实现:
public static String encode(String data) {return new String(Base64.encode(data.getBytes()));
}
public static String decode(String base64Data) {return new String(Base64.decode(base64Data));
}
Commons Codec 提供的 Base64 编码实现:
public static String encode(String data) {return Base64.encodeBase64String(data.getBytes());
}
public static String decode(String base64Data) {return new String(Base64.decodeBase64(base64Data));
}
上面让咱们用 Java 语言的实现来验证一下,咱们第二章节的推理是否正确吧,代码如下:
public static void main(String[] args) {
String ftd = "FTD";
String ft = "FT";
String f = "F";
System.out.println("FTD base64 编码:" + encode(ftd));
System.out.println("FT base64 编码:" + encode(ft));
System.out.println("F base64 编码:" + encode(f));
}
输入后果为:
FTD base64 编码:RlRE
FT base64 编码:RlQ=
F base64 编码:Rg==
能够看到,和咱们剖析所得的后果是齐全一样的。
查看残缺代码请拜访:
https://github.com/ForTheDevelopers/JavaSecurity
总结
Base64 是咱们在工作中常常用到,然而很少有人会深入研究一下它的实现原理,如果了解不当,甚至可能还会有人用它当做加解密用到业务零碎要害地位,可能会引发比较严重的结果,置信大家看完上述的内容后,应该对 Base64 编码曾经有了粗浅的了解了吧。
技术人,技术魂,每天肝一篇技术文,ヾ(◍°∇°◍)ノ゙哈哈~
对于作者
- GitHub:https://github.com/ForTheDevelopers
- 掘金:https://juejin.cn/user/1204720472953022
- CSDN:https://blog.csdn.net/ForTheDevelopers
- 知乎:https://www.zhihu.com/people/forthedevelopers
- segmentfault:https://segmentfault.com/u/for_the_developers
分割作者
- 微信号:ForTheDeveloper
- 公众号:ForTheDevelopers