协议演进 / BIP/比特币改进提案 / BIP-151
BIP-151
用临时 ECDH 密钥为选定的节点连接协商对称加密,使 P2P 流量可加密传输并能检出中间人篡改。本 BIP 目前处于已关闭状态。
一、档案卡
| 编号 | BIP-151 |
|---|---|
| 标题 | Peer-to-Peer Communication Encryption |
| 作者 | Jonas Schnelli <[email protected]> |
| 指定日期 | 2016-03-23 |
| 层级 | Peer Services(对等服务) |
| 类型 | Specification(规范类) |
| 状态 | Closed(已关闭) |
| 接替文档 | Proposed-Replacement: BIP-324 |
| 阅读版 | https://bips.dev/151 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0151.mediawiki |
二、放在哪一族
P2P 网络隐私族里管“加密”的那一篇。它有一篇直接的下游与一个正式的后继:
BIP-150:对等节点认证。认证必须建立在加密通道之上,用的正是本篇协商出的会话 ID;本篇只管把通道变密文,管不了“对面是谁”。
BIP-324:v2 P2P 加密传输协议。本篇档案序言明确记有 Proposed-Replacement: 324——本篇的接替文档。加密节点流量这件事,最终是沿着 324 那套设计落地的,不是沿着本篇。
读本篇的价值,在于看清 2016 年这套方案的设计取向:机会性、按连接选择、只加密选定的一部分对等连接,而不是把全网流量一刀切地改掉。
三、它要解决什么
原文的出发点:比特币节点之间的通信在当时完全不加密。由此带来两类问题:
- 安全上,链路上的第三方可以操纵流量(例如拦下某些命令),通信双方却无从察觉;
- 隐私上,大规模监控与分析变得很容易:网络服务商或任何中间人可以轻易识别出某个比特币用户、其掌控的地址与密钥,甚至与该用户的其他网络身份关联起来;一笔刚创建并广播的交易,其金额与收款方在链路上就是明文。对 SPV(轻)节点,这类影响尤为显著,也会削弱单个节点的抗审查能力。
原文也坦承边界:即便加密,报文的大小、发送间隔等特征仍在,按流量特征分析通信类型依然可能;比特币的信任模型也让这类风险在多数场景下不算致命——但“能显著抬高针对性分析的成本”本身就是目标。
已有的替代办法——VPN、Tor、stunnel、curveCP 等更低层级的加密机制——对 SPV 节点与常见的 DHCP/NAT 环境并不实用,搭建门槛也高。本篇要给出的,是一个节点软件内建、上手成本低的加密选项,且只加密选定的一部分远端节点连接。
四、规则本身
4.1 总则:双向各自协商
- 支持加密的节点必须接受来自所有节点的加密请求;
- 两个通信方向要各自独立做一次 ECDH 协商,因此一条双向连接使用两把对称密钥,一方向一把;
- 只有两个方向都协商成功之后,双方才可以发送加密消息;
- 协商必须在向对方发送任何其他消息之前启动;version 消息之后才到的 encinit 消息应被忽略。
4.2 密钥推导:ECDH + HKDF
双方各自生成临时(ephemeral)会话密钥对,交换公钥后用 ECDH 算出共享秘密,再用 HKDF(RFC 5869,哈希为 SHA256)推导:
- 提取:
PRK = HKDF_EXTRACT(salt="bitcoinecdh", ikm=ecdh_secret || cipher-type);把密码套件类型也算进输入,是为了防弱密码套件攻击; - 派生两把 32 字节密钥:K_1 用 info=“BitcoinK1”,K_2 用 info=“BitcoinK2”;
- 同时派生 256 位的会话 ID:
SID = HKDF_EXPAND(info="BitcoinSessionID", L=32),供 BIP-150 把加密会话与身份认证关联起来。
分工上,K_1 只用来加密报文的长度字段,避免从明文长度泄露消息大小;K_2 与 Poly1305 配合构成 AEAD(带认证的加密)来保护正文。
4.3 握手消息:encinit 与 encack
请求方生成临时会话密钥对,发送 encinit 消息,内含:
- 临时公钥(33 字节,压缩公钥);
- 对称密码类型(1 字节):原文只定义了 0 号,即 [email protected]。
应答方以 encack 回应,内含自己的临时公钥(33 字节);至此该方向的共享秘密即可算出。随后反方向必须再做一次同样的 encinit/encack,且第二个 encinit 必须使用相同的密码类型;第二次 encack 之前到达的未加密消息一律忽略。双向握手全部完成之后,线路必须切换为加密消息结构;此后再收到明文消息,应终止连接。
所用套件 ChaCha20-Poly1305 是 OpenSSH 的同名方案:ChaCha20 负责流加密,Poly1305 提供一次性消息认证。原文还引了一条性能判断:ChaCha20-Poly1305 的优化实现通常很快,按 Pieter Wuille 的初步分析,每字节的 CPU 开销甚至低于当时未加密格式所用的 SHA256。
4.4 加密消息结构
加密后的报文不再带 4 字节的网络魔数(network magic),结构为:
- length(4 字节):密文载荷长度;
- ciphertext payload:一段或多段密文(命令 + 消息数据);
- MAC tag(16 字节):128 位完整性标签。
随之而来的变化:原格式的 4 字节 SHA256 校验和不再需要(AEAD 已提供完整性);双方要各自跟踪已发消息的序号(uint32,可在 2^32−1 后回绕到零),用来拼出 64 位的对称密码 IV;解密后的明文仍是原有的一条或多条“命令 + 长度 + 载荷”消息,段数不显式声明。原文也专门提醒:4 字节长度字段理论上会要求高达 4 GiB 的消息缓冲,必须谨慎处理,且不得在认证成功之前就处理报文内容。
4.5 重新换钥(Re-Keying)
应答方可以用一条内容为 33 字节零的 encack 通知对方换钥,此后消息改用下一把对称密钥:新密钥 = SHA256(SHA256(session_id || 旧对称密钥))。换钥间隔属于节点策略,但最短不得少于 10 秒;且每发送或接收 1 GB 数据之后必须换钥(此条按 RFC 4253 对 SSH 传输的建议)。
4.6 明确不管的事:身份
原文明说本篇的风险所在:加密协商不包含任何身份认证,无法防范协商阶段的中间人攻击。对面究竟是谁,要由另一篇文档(即 BIP-150)在加密通道之上再解决。
兼容性方面,本篇向后兼容:不支持的节点会忽略 encinit 消息。
五、谁必须动
普通持币人:无直接关系。不改地址、不改交易、不上链;影响的只是节点之间线路上的字节形态。
钱包开发者:只有直连 P2P 网络的轻钱包才需要实现 encinit/encack 握手与 ChaCha20-Poly1305 加解密;通过节点 RPC 或服务商接口同步的钱包不涉及。
全节点与矿工:自愿实现。节点需要能响应加密请求、双向协商、维护序号与换钥;不实现的节点照常以明文与他人通信,对方也不得因此断开。
共识层:完全不触碰。本篇是传输层选项,加密与否不影响任何区块与交易的有效性判定。
六、现在算不算数,以及一个常见误读
状态为 Closed(已关闭),且档案序言已注明 Proposed-Replacement 为 BIP-324。也就是说,本篇这套“encinit/encack + ChaCha20-Poly1305”的具体设计没有成为节点间的通行标准;“给 P2P 流量加密”这个问题本身,则由接替它的 v2 加密传输协议以另一套方案承接。提案评论摘要在序言中记为“有争议;有人推荐,也有人不鼓励(Controversial)”,本页如实转述。
常见误读:
“BIP-151 加密之后,节点通信就既私密又可信了。”
只对一半。按原文,它提供的是保密性与完整性:窃听者看不懂、篡改会被 AEAD 的标签检出。但它明确不做身份认证——你加密通话的对象可能正是中间人本人。把“加密”直接等同于“对方可信”,恰恰是原文在风险一节里点名要防的误会。
七、延伸
- 阅读版:https://bips.dev/151
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0151.mediawiki
- 相关:BIP-150 对等节点认证、BIP-324 v2 P2P 加密传输协议(本篇的接替文档)
- 仓库总目录:https://github.com/bitcoin/bips
