gnupg 2.1.16 块等待熵

jas*_*yan 9 encryption gpg linux-kernel

从 2.1.16(当前为 2.1.17)发布的gnupg阻止仅在第一次调用时等待熵。

注意:这不是尝试生成密钥,只是为了解密文件并启动代理。

第一次启动 gpg-agent 时,无论是直接使用gpg2 file.gpg还是使用类似 的应用程序pass,都会出现 pinentry,一旦我输入密码并点击Enter它,它就会挂起大约 15 秒。

在 default-cache-ttl 窗口内的所有后续调用都会立即执行。

--debug-all模式下运行,发生挂起的时间段打印1

gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
...
Run Code Online (Sandbox Code Playgroud)

我安装了rng-tools来补充熵池:

cat /proc/sys/kernel/random/entropy_avail 
4094
Run Code Online (Sandbox Code Playgroud)

并与没有安装 rng-tools 或hasged相同版本的 gnupg 的机器相比,没有延迟:

cat /proc/sys/kernel/random/entropy_avail
3783
Run Code Online (Sandbox Code Playgroud)

因此,池中似乎有足够的熵。这在内核 4.8.13 和 4.9 上进行了测试。

gpg 使用不同的池吗?如何提供足够的熵,或以其他方式消除启动代理时的 15 秒延迟?



1.完整的调试日志

str*_*ika 2

我想我知道发生了什么事。在gnupg的agent/gpg-agent.c中,该函数处理来自libgcrypt的消息。

\n\n
/* This is our callback function for gcrypt progress messages.  It is\n   set once at startup and dispatches progress messages to the\n   corresponding threads of the agent.  */\nstatic void \nagent_libgcrypt_progress_cb (void *data, const char *what, int printchar,\n                             int current, int total)\n{\n  struct progress_dispatch_s *dispatch;\n  npth_t mytid = npth_self ();\n\n  (void)data;\n\n  for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)\n    if (dispatch->ctrl && dispatch->tid == mytid)\n      break;\n  if (dispatch && dispatch->cb)\n    dispatch->cb (dispatch->ctrl, what, printchar, current, total);\n\n  /* Libgcrypt < 1.8 does not know about nPth and thus when it reads\n   * from /dev/random this will block the process.  To mitigate this\n   * problem we take a short nap when Libgcrypt tells us that it needs\n   * more entropy.  This way other threads have chance to run.  */\n#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */\n  if (what && !strcmp (what, "need_entropy"))\n    npth_usleep (100000); /* 100ms */\n#endif\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后一部分 npth_usleep 是在 2.1.15 和 2.1.17 之间添加的。由于如果 libgcrypt 早于 1.8.0,这是有条件编译的,因此直接的修复方法是针对 libgcrypt 1.8.0 或更高版本\xe2\x80\xa6 重新编译 gnupg,不幸的是该版本似乎还不存在。

\n\n

奇怪的是,关于 libgcrypt 读取 /dev/random 的评论是不正确的。跟踪代理显示它正在从 /dev/urandom 读取并使用新的 getrandom(2) 系统调用,而不会阻塞。然而,它确实发送了许多 need_entropy 消息,导致 npth_usleep 阻塞。删除这些行可以解决问题。

\n\n

我应该提到 npth 似乎是某种协作多任务库,而 npth_usleep 可能是它的屈服方式,因此最好显着减少延迟,以防万一 libgcrypt 决定阻止某天。(1ms不明显)

\n