将 libsodium XChaCha20-Poly1305 用于大文件

Using libsodium XChaCha20-Poly1305 for large files

我正在查看 libsodium,特别是对称加密选项 XChaCha20-Poly1305。我无法理解的是 libsodium 似乎没有提供通常在加密库中找到的 "context/update/finalise" 工作风格。

libsodium 可以清楚地看出,XChaCha20-Poly1305 消息的大小有 "no practical limit"。但是实际上,如果我正在加密一个多 GB 的文件,我不太清楚您将如何使用 libsodium 来加密?因为显然您只会将 fread 缓冲区的内容传递给 crypto_aead_xchacha20poly1305_ietf_encrypt?

对于那些认为这是题外话的人的重要提示

迫于同辈压力,我确实删除了这个post。但是,我应@MaartenBodewes 的要求重新打开了它,他强烈认为它是切题的,而且强烈到他付出了一些努力来写一个答案。因此,出于对他的努力的尊重,我取消了 post 的删除。请给我更多 "off-topic" 条评论,我已经读够了!

在 libsodium 的介绍中写道:"Its goal is to provide all of the core operations needed to build higher-level cryptographic tools."

因此,Libsodium 是一个相对 高级库,它提供对底层结构的有限访问。


也就是说,使用 已验证的密码 加密如此大的文件存在一些固有的困难。问题是要么需要先验证真伪然后然后开始解密,要么需要先在线解密再验证验证标签。这反过来意味着如果验证失败,您必须写入/销毁内容。

通常你可以通过加密来解决这个问题,例如16KiB 左右的块,然后为块添加身份验证标记。当然,您需要确保增加随机数(确保流密码的计数器不重复)。这当然会增加一些开销,但没什么大不了的 - 无论如何你都会有一些开销。缺点是您不能再就地解密(因为那样会留下空白)。

如果你想做一个非常高级的方案,你也可以把所有的认证标签都放在最后。或者在内存中缓冲所有身份验证标签,并在所有收集到的标签上计算一个 (HMAC) 标签。

所以多次调用 crypto_aead_xchacha20poly1305_ietf_encrypt 可以被认为是一种选择。如果你这样做,你可能想计算一个文件特定的密钥,这样你就可以从零开始你的随机数。


如果您只想对存储的文件保密,您可以考虑省略身份验证标签。在这种情况下,您可以使用 int crypto_stream_xchacha20_xor_ic:

手动影响用于创建密钥流的计数器

This permits direct access to any block without having to compute the previous ones.

显然,您仍然可以使用 libsodium 中也提供的 HMAC-SHA-2 添加身份验证标签,但这会比使用 poly1305 慢很多。


最后,libsodium 是开源的。如果你非常勇敢,你可以进入血淋淋的细节并构建你自己的 context/update/finalize。该算法当然支持它(提示:如果你走这条路,在解密例程中永远不要缓冲身份验证标签或随机数 - 直接解密)。