作者:benma

来源:https://blog.bitbox.swiss/en/anti-klepto-explained-protection-against-leaking-private-keys/

原标题为:“Anti-klepto:BitBox02 如何保护你不泄露私钥”。原文出版于 2021 年。

“Anti-klepto” 是防范 “nonce 隐蔽信道攻击 ” 的保护措施。

Anti-klepto 的作用是什么?

BitBox02 这样的硬件签名器,会创建 “数字签名 ” 来授权你的交易。它们使用 私钥 来生成签名。如果不知道正确的私钥,就无法为一个公钥伪造签名(因此也无法盗窃用该公钥锁定的资金)。而一个签名的数学结构还包含了一个 nonce ,它是硬件签名器可以自由选定的一个随机数。

恶意的硬件签名器可以通过操纵这些 nonce,在成型的签名中泄露私钥。因为签名是交易的一部分,会永久记录在公开的区块链上,远程的攻击者可以读取它们、重构出私钥,获得受害者的资金的控制权。

我们可以让主机软件(比如 BitBoxApp)可证地为 nonce 贡献随机性,来防止这种操纵发生,从而缓解攻击的可能性。

这种攻击在两个方面尤其可怕:

  • 即使你在一个完全安全的环境下验证交易的所有细节,并使用完全 “空气隔离” 的装置来签名交易,你也依然没有保证;除非启用了 anti-klepto 这样的协议。
  • 这种攻击完全不涉及电脑和手机(这些主机设备)。哪怕你的硬件签名器所连接的电脑和手机完全没问题,也一样能奏效。

而 anti-klepto 协议可以阻止这种攻击,办法是让你的电脑或手机钱包软件来检查 检查 签名

为什么这能派上用场呢?

我们是 “深度防御” 和 “别信任、去验证!” 信条的忠诚信徒。

为了提高透明性、减少用户需要的对设备供应链的信任因素,我们持续推出特性和工具链来帮助你验证你拿到的 BitBox02 设备(及其生成的种子)的完整性和安全性,比如说:

  • 只有经过 Shift Crypto 公司签名过的固件才能运行在 BitBox02 上。
  • 每一款兼容的电脑和手机钱包软件都会自动执行见证检查(正品检查),已保证连接的 BitBox02 设备是由 Shift 出厂的,然后才能解锁设备。
  • 我们所有的代码都是开源的,包括 BitBox02 固件 和 BitBoxApp,还有我们供给第三方钱包集成的库。
  • 你可以从我们发布的源代码编译出固件,从而验证我们发布的固件二进制文件跟源代码是一致的。要了解编译指令,请看我们关于 “可复现编译” 的指南。
  • 你可以配置 BitBox02 先在屏幕上显示即将执行的固件的校验和,然后再执行它,从而在另一环节验证它跟正式发布的版本一致。
  • 从 01.2021 Monte Rosa 版本开始,你可以手动生成种子,不依赖 BitBox02 的随机数生成器,比如你可以摇骰子。请看我们的 “摇出你的比特币种子词”。

Anti-klepto 协议是这张清单上的最新条目。跟其它特性一样,它能提高供应链攻击的代价和精力。

操纵种子词的生成,以及,在 nonce 隐蔽信道中泄露种子词,可能是执行大规模攻击的最高效办法。这两个问题都在我们最新的 01.2021 Monte Rosa 版本中得到了解决。

极简背景知识:私钥与公钥

在比特币钱包中,用作私钥的就是一个很大的数字,非常大,以至于靠猜是猜不出来的,比如说:

92193805913277071008055984303319191614197341949664602874511898854633635443214

每个私钥都有一个对应的 公钥,公钥又会转化成钱包中的比特币地址。发送到某个地址的资金只能用对应的私钥来花费。光知晓一个公钥,并不能知晓关于其背后的私钥的任何事情。

如今,比特币钱包的工作模式已经不再是逐个生成私钥并保存起来,而是只保存一个 种子,用这个种子 钱包来按需要派生出子密钥(私钥和公钥)。这个种子,就是你在初始化 BitBox02 时要备份到你的 microSD 卡中、或者用 24 词的形式写在纸上的东西。

从一个私钥计算出其公钥的共识是 公钥 = 私钥 × G ,这里的 G 是一个预先确定的数值。

从技术上来说,公钥们形成了一个数学上说的 “群”,在这个群中,加法有自己的含义(乘法的含义也由此而来)。如果你想了解更多,这个播客系列 “椭圆曲线密码学:通用介绍” 是非常好的读物。

只不过,在这里,除法是做不到的(不然你就可以从公钥反算私钥了!)。除此之外,绝大部分常用的数学原理在这里也成立。分配律这样的数学原理依然成立:(a + b) x G = a x G + b x G 。这个原理使得钱包软件可以防止 nonce 隐蔽信道攻击,我们后面就会看到。

Nonce 隐蔽信道攻击

电子签名中有一部分叫做 “nonce”。一个 nonce 就跟一个私钥一样,但它是每当要生成签名的时候就随机生成一个。跟任何私钥一样,它也有对应的公钥 nonce x G 。这个公钥是签名的一部分,最终也会永远记录在区块链上(因为签名会放在交易中)。

因为在使用随机 nonce 时有许多陷阱,所以绝大部分钱包实现都已经切换成了使用 “ 确定性的 nonces”。这样就不依赖于随机数生成器了,而是通过对 私钥、待签名的消息(以及可选的额外数据) 运行哈希运算来得出一个 nonce 。不幸的是,光看这样一个 nonce ,你是无法分辨它是随机采集出来、还是确定性生成的,当然也无法看出它是不是恶意的 nonce 隐蔽信道攻击。

一个恶意的硬件签名器如果想抽取出其中的钱包种子 —— 再说一次,钱包中的所有其它私钥都是从这个种子生成的 —— 它只需要将种子词的一部分编码在 nonce 公钥中,这个 nonce 公钥因为是交易签名的一部分,会永久记录在区块链上。当出现在链上的恶意签名积累到一定数量之后,攻击者就能从中拼凑出你的种子。

恶意硬件签名器的障碍有:

  • 它需要尝试许许多多不同的随机 nonce,才能让 nonce 公钥展现出特定的模式。因为这个过程比较慢, 恶意硬件签名器一次往往只能影响整个签名的很少几个字节。
  • 签名还需要包含某种隐蔽的记号,这样攻击者才能在扫描区块链时分辨出来(并保证只有他自己能分辨出来)。

结果是,只靠一个签名是无法泄露种子词的,需要多个。取决于方法和环境,几十个签名足以泄露整个种子。

防范措施:anti-klepto 协议

通过限制硬件签名器自由选择 nonce 的能力,就能挫败这种攻击。为此,BitBoxApp(或其它能跟 BitBox02 搭配使用的软件)会要求硬件签名器先自己选出一个内部 nonce,但在最终用于签名的 nonce 中,还必须添加一个由软件选择的 nonce 。

整个协议按以下步骤执行,并且每当生成签名都要这样做。

请注意,我这里说的是协议的一个简化版本,为的是解释这个概念。完整的协议、所有的细节,其说明跟代码实现放在一起,可以在此处找到。

看:

硬件签名器先要承诺自己意图使用的 nonce ,办法是将 nonce 公钥(记为“设备 nonce 公钥”)发送给主机钱包软件:

设备 nonce 公钥 = 设备 nonce x G

把这个值发送给主机钱包软件,硬件签名器后面就无法再变换设备 nonce 了。

主机钱包软件自己随机采集一个 nonce,记为 “hostNonce(主机 nonce)”,将它发送给硬件签名器。

硬件签名器使用结合 nonce nonce = deviceNonce + hostNonce 来生成最终的签名。放在签名中的最终 nonce 公钥是:

nonce x G = (设备 nonce + 主机 nonce) x G

主机钱包软件可以通过检查下列等式,来验证自己的那一部分 nonce 输入被使用了、出现在了最终 nonce 公钥中:

nonce x G = 设备 nonce x G + 主机 nonce x G(分配律)

也即:nonce x G = 设备 nonce 公钥 + 主机 nonce x G

只需使用早前收到的 deviceNoncePublicKey ,主机钱包软件就能完成验证。如果验证失败,主机钱包软件会放弃操作、不广播这笔交易,防止设备隐蔽地泄露任何秘密。

这里面有一些细节,为了得到正确的实现,是非常重要的:

  • 在释放最初的 nonce 公钥之前,不能让硬件签名器拿到主机 nonce,不然的话,它就依然完全有机会操控最终的 nonce 。主机钱包软件必须保证这一点。
  • 硬件签名器不能为两个不同的主机 nonce 使用相同的设备 nonce,否则,私钥会立即泄露给主机钱包软件。所以,办法是让主机先给设备发送设备 nonce 的一个哈希值承诺。有了这个承诺,设备就能基于主机 nonce 来创建不同的 nonce 。

发布

Jonas Nick 最早为 Schnorr 签名实现了这套 anti-klepto 协议。基于这个实现,我为 ECDSA 签名做出了同样效果的实现,并在 secp256k1 代码库中打开了一个 PR 。ECDSA 签名方案是当前在比特币(以及其它许多山寨币)上服役的方案,所以支持它是让 anti-klepto 协议能够推向真实应用场景的前提。

我们在 BitBox02 的 9.4.0 版固件发布了对这套协议的支持(01.2021 Monte Rosa update )。BitBoxApp 从 4.25 版本开始,为 BitBox02 贡献 nonce 并验证其被用到了比特币交易或莱特币交易的签名中。在未来的版本中,还会支持 anti-klepto 协议用于以太坊交易的签名,以及用于使用比特币或以太坊公钥来签名消息。 未来,我们可能会强制执行这套协议(需要升级固件)。

我们所有的 BitBox02 开源软件库都已经升级为支持 anti-klepto 协议。也就是说,在支持使用 BitBox02 的第三方钱包,比如 HWI、Electrum、MyEtherWallet 等等中,都会自动获得支持。

为开源协作欢呼

尤为感谢 Stepan Snigirev 关注到了这个问题,并在他的博客文章中给了这个话题一个很好的解释。这篇文章是我为 BitBox02 和其它硬件签名器开发可以进入生产场景的 anti-klepto 协议实现的重要动机。

BitBox02 依赖于开源的 secp256k1 密码学代码库,它也是驱动 Bitcoin Core 全节点和钱包的密码学库。

非常感谢 Jonas Nick,他慷慨地审核了我的实现的多版迭代。由于 Jonas 忙于 BIP - Schnorr、MuSig2 以及其它有趣的项目,这个过程一度暂停。感谢 Andrew Poelstra 接手我的工作,看护它直至最终合并到 secp256k1-zkp 代码库。同样感谢 Tim Ruffing 提供了额外的审核。

我的工作的一大好处在于,它是开源的,成为了一个经过严格审核的代码库的一部分,所以可以用在任何地方。我们期待其它硬件签名器采用这套协议。Blockstream 已经宣布为他们刚刚发布的 Jade 硬件签名器添加了支持。

有用的资料

(完)