是编码。
base64根本不是什么加密,就是一种编码方式,你问为什么,且听我细细道来。
二进制我们都知道大家应该知道,机器语言一般都是二进制的,在一个字节( byte )上,是八个位( bit ),每位上可以存放 0 或者 1,通常一个字节可以存入一个 ASCII 码,两个字节存放一个国标汉字,现在大多数是 UTF-8 的编码,用的是三个字节。所以下面咱们以汉字为例,来说明 base64 为什么只是一种编码而不是一种加密方式。
吖
以《现代汉语词典》第5版第一页第一个字「吖」为例,UTF-8 编码下转为二进制,咱们先写一段简单的代码:
1 | for (let value of new Buffer.from('吖').values()) { |
简单来说就是「吖」占用了三个字节,每个字节分别是 229,144,150,转换为二进制编码就是「11100101 10010000 10010110」,共计二十四个位。
当使用 base64 编码之后,会以每三个字节为一组,把「11100101 10010000 10010110」转换成「111001 011001 000010 010110」,然后三字节就变成了四字节。用代码来写一下就是:
1 | let binary = ''; |
简单点来说就是三八二十四换成了四六二十四。那每个字节前面剩下的两个位,怎么办呢?嗯…我有 10 块,和我有 00000010 块,代表的意思一样,所以可以简单理解为在计算机中,没有就是 0。
但凭空多了一个字节,有什么好处呢?因为 base64 编码每个字节只写了六个位,所以一共对应的只有 2^6=64 个可打印的字符(其实 base64 的 64 是这个意思啦),在 Base64 中的可打印字符包括字母 A-Z、a-z、数字 0-9,这样共有 62 个字符,此外两个可打印符号在不同的系统中而不同。在 JavaScript 中,这两个字符是 + 和 /。
所以先把「111001 011001 000010 010110」转换为十进制,咱们来简单的修改一下代码:
1 | let binary = ''; |
按照编码表(第一位是 0 位,为 A)就能知道「吖」转为 base64 之后是「5ZCW」。
那么我上面算的这些对不对呢?咱们来验证下,JavaScript 提供了简单的方法:
1 | new Buffer.form('吖').toString('base64'); |
所以反过来一样可以知道「5ZCW」是「吖」,这也是 base64 只是一种编码而不是一种加密方式的原因。
注意:在浏览器中可以直接使用 btoa 来直接把普通字符串转换成 base64 字符串,但无法转换汉字,这时候需要先额外把汉字转换成其他编码
(比如 URI),但这样和直接转为 base64 的结果是不同的。