如何使用GnuPG和GNU parallel进行大文件并行加密?

8
我正在尝试编写一个使用GNU parallel、xz和GnuPG进行压缩/加密备份归档的并行脚本。脚本的核心部分如下:
tar --create --format=posix --preserve-permissions --same-owner --directory $BASE/$name --to-stdout . \
    | parallel --pipe --recend '' --keep-order --block-size 128M "xz -9 --check=sha256 | gpg --encrypt --recipient $RECIPIENT" \
    | pv > $TARGET/$FILENAME

没有 GnuPG 加密时,它运行得很好(解压和解包都可以),但添加并行加密后,无法解密,出现以下错误:
[don't know]: invalid packet (ctb=0a)
gpg: WARNING: encrypted message has been manipulated!
gpg: decrypt_message failed: Unexpected error
: Truncated tar archive
tar: Error exit delayed from previous errors.

因为未压缩的大小与gnu parallel的块大小(约125M)相同,所以我认为这与GnuPG对部分块加密的支持有关。我该如何解决这个问题?

知情,供参考

另一个与随机数生成有关的并行gpg加密问题

https://unix.stackexchange.com/questions/105059/parallel-pausing-and-resuming


在这里你可以做的最好的一件事是向gpg传递“-z 0”,以防止它尝试重新压缩xz的输出。这可能会将您的工作转换为IO绑定,并消除对GNU parallel的需求。这对我有用,但我要注意的是我使用的是zstd而不是“xz -9”。 - Dzamo Norton
3个回答

9

打包

tar --create --format=posix --preserve-permissions --same-owner --directory $BASE/$name --to-stdout . |
    parallel --pipe --recend '' --keep-order --block-size 128M "xz -9 --check=sha256 | gpg --encrypt --recipient $RECIPIENT;echo bLoCk EnD" |
    pv > $TARGET/$FILENAME

解压

cat $TARGET/$FILENAME |
  parallel --pipe --recend 'bLoCk EnD\n' -N1 --keep-order --rrs 'gpg --decrypt | xz -d' |
  tar tv

-N1 是必需的,以确保我们一次只传递一个记录。GnuPG 不支持解密多个合并的记录。


@Old Tange :我不知道 --rrs。使用自定义分隔符是个好主意。在你的命令中,我不能理解 -N1 选项。这个选项在这个上下文中是做什么用的?man 页面说:“当与 --pipe 一起使用时,-N 是要读取的记录数。这比 --block 稍慢。” - Yongbin Yu
谢谢您的快速回答。只是好奇,如果我错过了“-N1”选项,是否会并行传递多个记录到管道? - Yongbin Yu
1
在打包命令中添加参数“-z 0”到gpg将节省许多浪费的CPU周期,因为它停止尝试重新压缩xz的输出。 - Dzamo Norton

7
GnuPG不支持连接多个加密流并同时解密它们。您需要存储多个文件并逐个解密它们。如果我没记错的话,您的命令甚至混淆了所有并行GnuPG实例的输出,因此结果是更多或更少随机的垃圾。
无论如何:GnuPG还负责压缩,请查看--compression-algo选项。如果您喜欢使用xz,请应用--compression-algo none,这样GnuPG就不会尝试再次压缩已经压缩过的消息。现在,由于CPU指令的大规模支持,加密比以往任何时候都更快, xz-9可能实际上比加密更耗费时间(尽管我没有对此进行基准测试)。

哇!非常好的答案和问题编辑,谢谢。这就是我想知道的。我不知道 gpg 对压缩的处理,我会在我的工作中尝试 --compression-algo none。正如你所提到的,对于几个千兆字节的文件,使用 xz -9 是一个巨大的过程,而 gpg 加密的过程也需要一定的时间。无论如何,我将报告两个测试的执行时间。 - Yongbin Yu
1
如果你能获取到足够新的支持软件,或许可以看一下Facebook的新zstd算法。一些基准测试声称,在竞争性压缩比下,它具有更优秀的CPU负载表现。虽然可能达不到xz -9的水平,但是却可以在更小的计算开销下实现。 - Jens Erat
是的,我已经花了一些时间将 Facebook 的全新 zstd 算法应用到管道处理上,但是 zstd 的进程创建行为与 xz、gzip 不同。因此,我成功地创建了并行压缩的 zstd 存档文件,但它的压缩比和时间都不如旧的 xz -9 设置。看来需要更多的研究。 - Yongbin Yu
在我的gpg(1.4.18 / Debian)中,设置压缩级别的选项是“--compress-level”,没有名为“--compression-algo”的选项,因此我只在我的脚本中设置了“--compress-level 0”。 - Yongbin Yu
这里是简单的基准测试数据。(11.9GiB tar.gz.xz)
  1. tar + 并行 xz + 单个 gpg 压缩:3022 秒
  2. tar + 并行 xz + 单个 gpg 无压缩:2550 秒(比原始速度快15.6%)
  3. tar + 并行 xz 和 gpg 无压缩:2873 秒(比原始速度快4.9%,但不可用
第三个命令显示了时间方差较高,因为获取了随机种子条件。最终我选择了tar + 并行 xz + 单个 gpg 无压缩组合。
- Yongbin Yu

0
这主要是一个 GPG 问题。GPG 不支持多线程,而且可能永远不会支持。你可以在网上搜索原因。
甚至在gpg v2中情况变得更糟:您甚至无法并行运行多个gpg v2实例,因为它们都会锁定正在执行所有工作的gpg-agent……也许在进行大规模加密时我们应该寻找替代方案。

https://answers.launchpad.net/duplicity/+question/296122

编辑:不。可以同时运行多个gpg v2实例,而不会对gpg代理造成任何问题。


从技术上讲,这涉及到另一个问题:OpenPGP指定使用CFB模式变体,不支持多线程加密,因此您必须启动多个单独的加密流(您已经这样做了)。当然,第二个引用可以通过运行多个线程或实例来解决(如果不支持,则是GnuPG的限制)。 - Jens Erat

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