虽然本篇文章的前缀是 加密算法,但是希望大家不要误解,Base64 并不是一种加密算法
可能有朋友在不了解 Base64 的情况下,将其误用于数据加密或数据校验。乍一看,Base64 编码过的字符串有一种被加密的感觉,但是该字符串会存在许多 Base64 的特征,例如字符串中会出现 +
或 \
两种字符,末尾通常会有一个到两个 =
。只要发现了这些特征,那么这个字符串大概率就是一个经过 Base64 编码后的字符串,此时无需任何额外信息即可轻松解码得出原始文本。
Base64 由来
我们知道在计算机中任何数据都是按字节存储的,一个字可表示的范围是 0 ~ 255,其中 ascii 值的范围为 0 ~ 127,而超越 ascii 范围的 128 ~ 255 之间的值是不可见字符,同时 ascii 中也包含部分不可见字符。
当不可见字符在网络上传输的时候,往往要经过多个路由设备,由于不同的设备(特指老的路由设备)对字符的处理方式有一些不同,这样那些不可见字符就有可能被处理错误,这是不利于传输的。所以就先把数据做一个 base64 编码,统统变为可见字符,也就是 ascii 可表示的可见字符,确保数据可靠传输。
对于现在的路由设备,只要是文本字符都可以直接在网络上传输。但是对于二进制格式的数据(图片,音频,视频等),我们一般都要把这些二进制数据转为文本字符后进行网络传输。
Base64 简介
之所以称为 Base64,是因为其使用了 64 个字符来对任意数据进行编码,同理还有 Base32
, Base58
(用于产生 Bitcoin 的钱包地址)等编码。
一个标准的 Base64 使用的 64 个字符为:
A-Z
a-z
0-9
+, /
这 64 个字符是各种字符编码(例如 ASCII
)基本字符集。
编码原理
使用 Base64 进行编码,大致可以分为 4 步:
- 将原始数据每三个字节作为一组,一共是 24 个 bit
- 将 24 个 bit 分为四组,每组 6 个 bit
- 在每组前面加两个 00,扩展成 32 个 bit,即四个字节
- 根据下标,得到扩展后每个字节的对应符号
因为,Base64 将三个字节转化成四个字节,因此 Base64 编码后的文本,会比原文本大出三分之一左右。
英文编码
- 第一步,
L
、o
、L
的 ASCII 值分别是 76、111、76,对应的二进制值是 01001100、01101111、01001100,将它们连成一个 24 位的二进制字符串010011000110111101001100
- 第二步,将这个 24 为的二进制字符串分成 4 组,每组 6 个二进制位:010011、000110、111101、001100
- 第三步,在每组前面加两个 00,扩展成 32 个二进制位,即四个字节:00010011、00000110、00111101、00001100,它们的十进制分别是 19、6、61、12
- 第四步,根据上表,得到每个值对应 Base64 编码,即
TG9M
中文编码
汉字 棋 如果转化成 Base64 编码?
需要注意的是,汉字本身具有很多种编码,例如 gb2312
,utf-8
,gbk
等,每一种编码的 Base64 对应值都不一样。下面的例子以 utf-8 为例:
首先,棋 的 utf-8 编码为 E6A38B
,写成二进制就是三字节的 11100110 10100011 10001011
。将这个二进制字符串按照上边的规则,转换成四组一共 32 位的二进制值 00111001 00101010 00001110 00001011
,相应的十进制数为 57、42、14、11,它对应的 Base64 值就是 5qOL
补码
-
两个字节
例如英文字符
PY
,我们仅能得到 2 个字节,也就是 16个二进制位。首先,按照上面的规则,转成三组,最后一组除了前面加两个 0 以外,后面也要加两个 0,这样就得到了一个三位的 Base64 编码,最后在结尾补上一个=
号
-
一个字节
一个字节的情况:将这一个字节的 8 个二进制位,按照上面的规则转成两组,最后一组除了前面加两个 0 之外,后面再加 4 个 0。这样得到一个二位的 Base64 编码,再在末尾补上两个
=
号
解码
解码就是对编码的逆向操作,但是需要注意一点:对于最后的两个 =
字符,转换成两个 A
字符,再转成对应的两个 6 比特二进制值,接着转成原始字符之前,需要将最后的两个 6 比特二进制值丢弃,因为它们实际上不携带有效信息
特殊变种
标准的 Base64 并不适合直接放在 URL 里传输,因为 URL 编码器会把标准 Base64 中的 /
和 +
字符转变为 %XX
的形式,而这些 %
号在存入数据库中时还需要再进行转换,因为 ANSI SQL 中已将 %
号用作通配符
-
用于URL的改进Base64
它不在末尾填充
=
号,并将标准 Base64 中的+
和/
分别改成了-
和_
,这样就免去了在 URL 编解码和数据库存储时所要做的转换,避免了编码信息长度在此过程中的增加 -
用于正则表达式的改进Base64
将
+
和/
改成了!
和-
,因为+
,*
在正则表达式中都有可能具有特殊含义