Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base64 编码原来这么简单 #51

Open
brickspert opened this issue Jun 5, 2022 · 2 comments
Open

Base64 编码原来这么简单 #51

brickspert opened this issue Jun 5, 2022 · 2 comments

Comments

@brickspert
Copy link
Owner

brickspert commented Jun 5, 2022

做了六七年程序员,经常用到 Base64 编码,但对于为什么要用,以及它的原理,一直是不求甚解。最近在某本书上看到了 Base64 的编码原理,原来这么这么这么简单。

Base64 解决了什么问题

假如我们要在网络中传输下面的问题

你好  小朋友

我是砖家

你是谁?

这段文本中包含了空格、换行、回车等不可见字符,在网络传输中,各个设备对不可见字符处理机制可能不同,会存在信息传输错误的情况。
此时我们就需要一种编码机制,把不可见字符统统转成可见字符。

Base64 编码原理

接下来我们通过将 abcd 4 个字符转为 Base64 编码,来了解下它的原理。

  1. 把字符三三分组,不够时通过 0 补齐。比如 abc三个字符归一组,d 不够三位,通过 0 补齐为 d00

image.png

  1. 把字符转换成二进制 ASCII 编码

image.png

  1. 把转换后的二进制,每六位分隔开

image.png

Q:为什么第一步需要分三个字符一组?

A:因为 ASCII 码每个字符是 8 位二进制,3 * 8 = 24。正好可以被第三步拆分为 4 个 6 位二进制,4 * 6 = 24。

  1. 6 位二进制能代表 0-63,我们有一个彩虹表,可以将 0-63 分别对应一个字符,彩虹表如下:

image.png

通过彩虹表,我们可以将每 6 位分割后的二进制做一次转换

image.png

需要注意的是,凡是补位产生的 0,需要用 = 来表示。所以最后的两位都是 =

最后 abcd 转换为 Base64 编码后为 YWJjZA==,整体原理还是比较简单的,不涉及到高深的算法。

Base64 周边

  1. 由于 Base64 转码后会包含 +/=字符,在 URL 不能正常传输。所以有一种 URL 友好型的 Base64 编码,它存在使用 _-来代替 +/,并且不在末尾追加 =
  2. Base32、Base16 的原理和 Base64 基本一致
  3. Base64 并不适合加密,因为解密太简单了
  4. 汉字通过 gb2312utf-8gbk编码后,即可转成二进制处理。这里借用网上的一个图片说明:
    image.png

Base58 与 Base58Check

Base58 是比特币在生成钱包地址时使用的一种编码形式。它和 Base64 的主要区别是去掉了肉眼容易看错的字符 0(零)、O(大写字母 O)、I(大写字母 i)、l(小写字母 L)和几个影响双击选择的字符:/ 和 +
这种编码的目的比较简单,就是防止在转账时,看错账号,转错账。
Base58 的原理更简单一些,只涉及到进制的转换,大致步骤如下:

  1. 将字符转成 ASCII 码
  2. 将 ASCII 码转换成 58 进制
  3. 通过彩虹表映射即可

比如 abcd转换:

  1. 转成 ASCII 码 97-98-99-100
  2. 转换成 58 进制 3-28-21-49-5-22
  3. 通过如下彩虹表映射为 3VNr6P

image.png

Base58Check 编码,顾名思义是可以对 Base58 编码进行检查。
比如我在传输 qH912cvztx编码时,如果网络异常等各种原因,导致数据错乱或丢失,接收方要能够识别出来数据有问题。
Base58Check 编码基本原理如下:

  1. 在 data 前面添加一个版本标识 prefix,用来识别编码的数据类型,比如比特币地址的前缀是 0(十六进制是 0x00)
  2. 通过 hash 算法计算 prefix + data的 hash 值:SHA256(prefix + data)
  3. 将生成的 hash 值截断为前四位,拼接到后面 prefix + data + 4 位 hash
  4. 将上一步生成的结果进行 Base58 编码计算,得到最终结果
@ZhaoTim
Copy link

ZhaoTim commented Jun 18, 2022

写得很清楚,连我这个小白都看懂了,感谢~
不过在例子中倒数第三个字符为什么会被转成base64编码里的A呢?,它的二进制也都是0啊。
image

@brickspert
Copy link
Owner Author

写得很清楚,连我这个小白都看懂了,感谢~ 不过在例子中倒数第三个字符为什么会被转成base64编码里的A呢?,它的二进制也都是0啊。 image

彩虹表对应的额,彩虹表上 0 对应 A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants