Base64编码原理探究

Base64背景

维基百科的解释

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2^6^=64,所以每6个bit为一个单元,对应某个可打印字符。3个字节有24个bit,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Za-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。

由来及场景

在参数传输的过程中经常遇到的一种情况:使用全英文的没问题,但一旦涉及到中文就会出现乱码情况。与此类似,网络上传输的字符并不全是可打印的字符,比如二进制文件、图片等。Base64的出现就是为了解决此问题,它是基于64个可打印的字符来表示二进制的数据的一种方法。

电子邮件刚问世的时候,只能传输英文,但后来随着用户的增加,中文、日文等文字的用户也有需求,但这些字符并不能被服务器或网关有效处理,因此Base64就登场了。随之,Base64在URL、Cookie、网页传输少量二进制文件中也有相应的使用。

通常使用的字符

使用的字符包括大小写英文字母各26个、数字10个、加号+和斜杠/,共64个字符,等号=用来作为后缀用途。

算法简介

编码过程
  • 通常情况

1565001808032.png

  1. 将待编码的字符串中各个字母的ASCII码查出.
  2. 将ASCII码转化为8位2进制表示,如文本M的ASCII码为77,用二进制表示则为01001101.
  3. 由于每6个bit为一个单元,所以每6个二进制位转化成一个十进制数,即编码结果的ASCII码. 如010011计算可得19.
  4. 转化所有编码结果即可.
  • 当字节不能被3整除时:

1565001979601.png

  1. 当无法被整除时,base64要在后面添加\0凑齐3n位,使二进制序列的长度成为24的倍数(6和8的最小公倍数).
  2. 由于不断补0,对应产生的空字符将用等号=填充,所以等号的个数必为0个,1个或2个.
  • 其他场景

    标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的/+字符变为形如%XX的形式,而这些%号在存入数据库时还需要再进行转换,因为ANSI SQL中已将%号用作通配符。

    1
    2
    3
    4
    5
    6
    
    import base64
    
    encode_str = base64.b64encode('ac>'.encode('utf-8'))
    print("result: ", encode_str)
    url_safe_encode_str = base64.urlsafe_b64encode('ac>'.encode('utf-8'))
    print("result: ", url_safe_encode_str)
    

    运行结果:

    1
    2
    3
    4
    5
    
    [Running] python -u "d:\urlsafe.py"
    result:  b'YWM+'
    result:  b'YWM-'
    
    [Done] exited with code=0 in 0.424 seconds
    
解码过程

去掉末尾的等号=。剩下的Base64字符,每8bit组成一个8bit字节,最后剩余不足8位的丢弃.

总结

一般来说,由于使用base64编码后的长度通常是原字符长度的4/3倍.
其实在补0的问题上,我也疑惑过为什么要一直补到24的倍数. 实际上这样做不仅是实现上的问题,而且当两个编码结果进行拼接之后,解码过程也能顺利进行.这样一想,应该就能很好理解了.

最后更新于 Aug 19, 2019 00:00 UTC
吾生也有涯,而知也无涯
Built with Hugo
主题 StackJimmy 设计