为什么atob和btoa不可逆?

6
我正在尝试找到一种简单的方法来记录并临时混淆我用Markdown编写的“测验”问题的答案。(在演示期间,我会告诉学生测验答案,因此我不需要任何安全加密。)我认为我可以使用atob('message I want to obfuscate') ,然后告诉学生他们可以在开发者工具面板中使用btoa() 来反转该过程。但是以下内容并不返回“one”:
btoa( atob('one') )

有人知道为什么这个函数没有返回'one'吗?还有其他内置于JavaScript中的方法可以使用,用来松散地加密和解密信息吗?(我正在与绝对初学者一起工作,他们可能会被函数所搞糊涂,并且在尝试向页面添加库时会非常困惑。)


4
那不是颠倒了吗?也就是说 atob(btoa("one")) - George
1
好的,非常感谢! - duhaime
2
@george 仍然有趣的是,它不起作用反过来。 - Jonas Wilms
2
是的,我同意。值得注意的是,这个空间是非欧几里得的。我把它恢复了,因为几年后我自己可能会搜索这个... - duhaime
3个回答

3

这就是原因。

在Base64编码中,输出编码后的字符串长度必须是3的倍数。如果不是,输出将会使用额外的填充字符(=)进行补齐。在解码时,这些额外的填充字符将被丢弃。

var string1 = "one",
  string2 = "one2";

console.log("Value of string1", string1)
console.log("Decoded string1", atob(string1))
console.log("Encoded string1", btoa(atob(string1)))
console.log("-------------------------------------")
console.log("Value of string2", string2)
console.log("Decoded string2", atob(string2))
console.log("Encoded string2", btoa(atob(string2)))


为什么编码字符串被填充为4个字符而不是3的倍数?你有任何参考资料吗?能否更准确地解释一下,以便我们能够理解? - Dan Froberg
如果你使用 atob 进行编码,然后填充为每组4个字符。如果你使用 btoa 进行编码,那么填充为每组3个字符。使用 atob 进行编码会得到比使用 btoa 进行编码更短的字符串。 - Dan Froberg

1
正如@george指出的那样,在使用atob()之前必须使用btoa()
atob( btoa( 'hello' ) )

即使btoa将Base64和DataURL转换为8位二进制表示,这并不是一个好的结果,因为btoa("abc")是4个字符,但atob("abc")将其压缩为2个字符。它可以进一步压缩为1个字符,因为JS使用16位字符串。 - Dan Froberg
你是在暗示有一些ASCII字符串,对于这些字符串,atob(btoa('hello'))不会返回输入的字符串吗? - duhaime
我完全不建议这个答案,因为正确的填充是要先执行atob。你有一个6位ASCII字符串(Base64,其中有2个8位未使用),然后得到一个填充了8位字节的二进制字符串。这就是目的;为了获得更短的字符串以便存储或发送。btoa会扩展字符串;除了解码数据之外没有任何好处。 - Dan Froberg
1
@DanFroberg 你的目的是获取较短的字符串。没有人以这种方式使用它,因为它不起作用。对Base64编码进行解码并不能成为对任意Base64字符字符串进行压缩的形式。 - Mark Adler
我以这种方式使用它,并将DataURI图像以超过50%无损压缩的方式存储在本地存储中。 - Dan Froberg

1
btoa是二进制到ASCII的意思:输入可以是任何类型的二进制数据(文本、图像、音频等),输出是ASCII编码,即一个ASCII子集,它是一个只包含大写字母、小写字母、数字、逗号、加号、斜杠和等号(只用于填充结尾)的文本字符串。 atob是ASCII到二进制的意思:输入必须是Ascii的子集,即Base64编码的结果。输出可以是任何类型的数据(文本、图像、音频等)。

你的回答说它是可逆的:二进制 <--> ASCII - Dan Froberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接