最近开发过程中经常会需要Base64编码,MD5,加密等功能,这些频繁使用的小工具要经常到网上找,而且还都不太好用,就自己开发了一个,codoolo。在实现Base64的过程,也学到了很多。这篇文件记录Base64相关的知识,欢迎指正。

Base64是什么?

Base64早已经被广泛使用了,尤其是Multipurpose Internet Mail Extensions (MIME)。

wikipedia中对Base64的定义:

Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation.

简单来说,Base64使用了指定的64个字符对数据编码,而这64个字符中不包括特殊字符(以免被一些应用认为是控制字符,如果ftp,ssh等),这样经过编码的数据可以在网络中安全的传输。

如何实现Base64?

首先需要挑选64个字符。RFC 4648定义了Base64的字符集:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

下图显示如何将字符串“xyz”编码为“eH16”的过程

steps to encode 3 chars

步骤:

  1. 把每个字符转换为整数,也就是字符在ASCII中的位置
  2. 将整数转换为二进制表示
  3. 每六位一组,转为整数,并在上面的Base64字符集中找到该整数所在位置的字符
  4. 将得到的字符连接起来,得到最终的结果

第二步和第三步其实是一系列位操作,并不需要真的转换,这里为了将编码过程阐述清楚,加了这两个步骤。

由于6位正好可以表示64,所以每3个8位的字符(24bit)可以编码为4个Base64字符(4个6bit=24bit)。但编码后的每个字符的存储仍然需要8位。这意味着Base64编码后的存储空间增加了1/3

由此认识到:

Base64使用6 bits重组数据,但重组后的每个字符仍然需要8 bit的存储空间。所以Base64是用较小的字符集表示数据,但存储空间却因此增加了,所谓有一利必有一弊。

URL和文件名

在上面的Base64字符集中包括了 '+/' ,而一般的URL和文件名中,不能使用这两个字符,所以RFC4686提议使用另外一个字符集:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_

而具体用哪个字符集,要考虑使用的场景。比如只是在项目内部使用,编解码都可控,那么就可以使用第二个,甚至可以使用一个自定义的字符集。但如果是将数据给第三方,那么使用第一个字符集更好,因为大部分库的实现都使用了第一个字符集。

如果数据的长度不是3的倍数怎么办?

我们刚刚说了如何将3个字符应用Base64编码,但如果字符串的长度不是3的倍数怎么办?

如果最后还有两个字符需要编码:
steps to encode 2 chars

比如"xy",2个字符有16 bits,那么前12 bits可以编码为"eH",对于剩下的4 bits,在右侧填充2个0,所以第三个字符是"k"。有时,网络中传输的数据长度是未知的,这时为了确定知道数据是否截止,则需要将编码的数据补齐为4的倍数。对于Base64编码,使用 = 来补齐,也就是第65个字符

如果最后只有一个字符,过程类似:

steps to encode 1 char

需要注意的是,最后使用了2个 == 来补齐。

请问,如果一个Base64编码的最后有3个=,即===,这是一个合法的Base64编码么?

如果数据不是ASCII码呢?

我们上面讨论编码的时候,都假设输入的是ASCII,即字符是0x00-0xFF之间的。那如果输入的字符是UTF-8呢?比如:

“こんにちは” 或者 “你好”

一般有两种方式来处理:

  • 在编码前转义字符串
  • 将UTF-8转为bytes

所以在实现codoolo时, 如果输入的是非ASCII码,会提示选择一个转换器:

show converter for non ASCII

如何解码?

了解了编码过程,相信解码就比较简单了,也就是将上面的过程逆向执行就可以。

还有什么?

说实话,我一直在使用Base64编码,到从没想过一个Base64编码也要有这么多需要注意的地方,而且还有问题:

  • 当将汉字等编码后,在解码时如果直接输出汉字?
  • Base64使用了更多的存储空间,那么是不是可以使用Base128呢?
  • 如果我使用一个特殊的字符集,这样编码出来的数据有多安全?容易破解么?
  • 如何提高编解码的效率?

我们以后接着聊。


CodeLoam
27 声望1 粉丝

引用和评论

0 条评论