base64编码_彻底弄明白Base64 编码

Base64 encoding/decoding常见于各种authentication和防盗链的实现当中。彻底搞懂它绝对提升团队troubleshooting的底气。我们从纯手工方式编码解码开始,然后看看学到的技能怎么样应用在实际的troubleshooting 中。准备工作:

  • 我们应知道一个byte有8个bits,并且知道怎么表示它。
  • 我们应该comfortable with hex, binary and decimal 之间的conversion.
  • 有一张现成的ASCII table. (网上有很多,我下面附一个直接带binary value的)

e98ac3b5d8b31687ff588e3c27c832e7.png
  • Base64 Table

2c3309c19858e4d0ca427c052009d5a7.png

Base64 Encoding的原理
大白话是这样。给定一个bits序列,从最左开始,按顺序每6-bit 为一组进行分组,这样每一组可以表示最多2的6次方,也就是64个字符。这是为什么它叫Base64的原因。
这样分组,最后即最右边的一组如果正好有6-bit, 分组就完成。如果不够6-bit, 就要做一个alignment / padding的处理。有两步。第一步,用binary 0 (bit 的值为0)补齐到6-bit. 如果补过的bit 序列正好落在byte boundary,则分组完毕;如若不然,继续第二步,补到下一个最近的byte boundary, 不过不是用0去pad, 而是用等号字符“=”, 用1个或者2个等号去补, 别忘了,一个等号占6个bits.
用数学的方式正规一点的描述是这样。
给定一个长度为L的bit 序列,L可以被8整除 ( 这也是byte boundary含义), 我们需要找到两个正整数M和N, 使得: L <= M <= N, 其中 M要能够被6整除, N is either L or L + 8.
根据这个描述可以得出下面这些结论:

  • 最后得到的长度为N的bit 序列也是落在byte boundary上,即N可以被8 整除。
  • L除以6的余数只有三种可能: 0,2, 4, 对应于三种不同的padding scenarios.
  • M - L 的 值只可能为: 0, 2, 4, 道理同上
  • N – M的值只可能为: 0, 6,12, 同样的,这是对应于三种不同的padding scenarios.

纯手工Base64编码
Given an input string “a”,
Step 1: 将它convert 成 bit 序列
查ASCII table, 我们得到它的binary value 即 bit 序列: 01100001
这是一个长度为8的初始序列。
Step 2: 按6个bits 一组分组
011000 01
Step 3: 最右组只有2 个bit, 不够6 bits, 需要补4个0
011000 010000
至此我们可以得到两个字符:
011000 = 2 ** 4 + 2 ** 3 = 16 + 8 = 24, 查Base64 table, 对应于24的字符是 Y.
010000 = 2 ** 4 = 16, 同样查Base64 table, 对应于16的字符是 Q
很多Base64的实现,到这就结束了。小写 a, 经过Base64编码之后就是YQ.
Step 4: 这原始bit 序列长度为8, Step 3补了4个0, 变成12,不能被8整除,继续补。
我们知道从12开始,下一个被8整除的值是24, 所以我们要补24 – 12 = 12个bits. 在这种情况下我们补等号字符,一个字符占6 bits,所以我们补两个”= “.
如果做了这一步,小写 a, 经过Base64编码之后就是YQ== .纯手工Base64 解码
Given YQ==,
Step 1: 去掉“=”的padding, 得到 YQ, 同时知道pad了12 bits 到byte boundary.
Step 2: 根据Base64 table convert “YQ” to bit 序列 011000 010000
Step 3: 去掉 最右边pad的4个0
因为原始字符也就是要decode过去的字符是跳 8的,现在有12 bits, 很快可以确定最右4 bits 是padding.
从这种工作方式我们可以看到,既然最右4 bits无论如何都是要去掉的,这4 bits 可以是任何2 ** 4 = 16个值中的一个,而不影响decoding的结果。举几个例子:
0110000 010001 = YR
0110000 010010 = YS
0110000 010011 = YT

0110000 011110 = Ye
0110000 011111 = Yf
下面是用Python Bas64 module decoding的结果,验证上面所讲。
>>> base64.b64decode("YR==")
'a'
>>> base64.b64decode("YT==")
'a'
>>> base64.b64decode("YU==")
'a'
>>> base64.b64decode("YV==")
'a'
>>> base64.b64decode("YW==")
'a'
>>> base64.b64decode("YY==")
'a'
>>> base64.b64decode("YZ==")
'a'
>>> base64.b64decode("Ya==")
'a'
>>> base64.b64decode("Yb==")
'a'
>>> base64.b64decode("Yf==")
'a'
>>> base64.b64decode("Ye==")
'a'
>>>
Step 4: 按8-bit 分组, 得到 011000 01, 这个就是”a”.实例分析
Linkedin发现如果他们修改防盗链token的最后一位,authentication仍然可以通过,要我们解释。
Token in question是这样的:
bs3xODAExQFZthY2LF1EqbuVtq4veLftiHILz3pXn13Ai5DzRYmdCZ8O9FAQwI4zceyBpEJO6secbKz9rGNMfBVeNaplwLNVqQwAXSR-grVQGJkz91pqdmVBbrwCpGto5IazBV8XDMJUIGCGZOdld2REqemD4cvDoLdeN3itZirB2FGfMHPxhP0
如果把末尾0换成1,2, 3, authentication 仍旧可以通过。
前面学到的东西可以马上应用。思路是这样的:
Token 长度为183, 所以bit 序列的长度为183 * 6 = 1098. 因为1098 没有落在byte boundary, 我们可以立即确定encoding 的Step 4省略了,即没有pad “=”.
因为1098 / 8 = 137 r2, 我们可以确定 最右的2 bit 是padding. 如前所述, 这两个bits 可以是 任何 2 ** 2 = 4个值中的一个,而不影响decoding的结果。
00 = 0
01 = 1
10 = 2
11 = 3
至此Linkedin 的问题彻底解释清楚。
读了这一篇,你应该可以回答为什么有的Base64-encoded的values 末尾没有等号,有的有一个等号,有的有两个等号,以及为什么多个values会decode到相同的value. If necessary, you should be able to base64 encode and decode pretty much anything MANUALLY.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值