如注释中所述,使用base64以文本形式发送二进制数据。


import base64
def xor_strings(xs, ys):
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys)).encode()
# ciphertext is bytes
ciphertext = xor_strings("foo", "bar")
# >>> b'\x04\x0e\x1d'
# ciphertext_b64 is *still* bytes, but only "safe" ones (in the printable ASCII range)
ciphertext_b64 = base64.encodebytes(ciphertext)
# >>> b'BA4d\n'

现在我们可以传输字节:

^{pr2}$

收件人可以通过以下方式检索原始邮件:

# ...reading bytes from a file (or a network socket)
with open('/tmp/output', 'rb') as f:
ciphertext_b64_2 = f.read()
# ...or by reading bytes from a string
ciphertext_b64_2 = safe_string.encode('ascii')
# >>> b'BA4d\n'
# and finally decoding them into the original nessage
ciphertext_2 = base64.decodestring(ciphertext_b64_2)
# >>> b'\x04\x0e\x1d'

当然,在将字节写入文件或网络时,首先将其编码为base64是多余的。如果密文是唯一的文件内容,则可以直接写入/读取。只有当密文是更高结构(JSON、XML、配置文件…)的一部分时,才有必要再次将其编码为base64。

关于“解码”和“编码”两个词用法的注释。在对字符串进行编码意味着将它从抽象意义(“字符列表”)转换为可存储的表示(“字节列表”)。此操作的确切结果取决于所使用的字节编码。例如:ASCII编码将一个字符映射到一个字节(作为权衡,它不能映射Python字符串中可能存在的所有字符)。

UTF-8编码将一个字符映射为1-5个字节,具体取决于字符。

解码一个字节数组意味着将它从“字节列表”重新转换回“字符列表”。当然,这需要事先知道字节编码最初是什么。

上面的ciphertext_b64是一个字节列表,在Python控制台上用b'BA4d\n'表示。

由于base64是ASCII的一个子集,当打印到控制台时,它的等价字符串safe_string看起来非常相似'BA4d\n'。

然而,数据类型仍然有根本的不同。不要让控制台输出欺骗你。