BOLT 8:加密和认证的传输

  • lightning
  • 发布于 2023-05-13 13:27
  • 阅读 22

本文档是闪电网络BOLT 8规范,详细描述了闪电网络节点之间加密和认证的传输协议。该协议使用Noise_XK握手进行密钥交换,并通过ChaChaPoly-1305算法加密所有通信数据,以保证节点间通信的保密性和完整性,同时包含了握手过程、消息加密、密钥轮换以及安全考虑等多个方面的内容。

BOLT #8: 加密和认证传输

闪电网络节点之间的所有通信都经过加密,以便为节点之间的所有记录提供保密性,并且经过身份验证以避免恶意干扰。每个节点都有一个已知的长期标识符,它是比特币 secp256k1 曲线上的公钥。这个长期公钥在协议中用于建立与对等点的加密和认证的连接,并且可以认证代表节点发布的任何信息。

目录

密码消息概述

在发送任何闪电网络消息之前,节点必须首先启动密码会话状态,该状态用于加密和验证节点之间发送的所有消息。此密码会话状态的初始化完全独立于任何内部协议消息头或约定。

两个节点之间的记录分为两个不同的部分:

  1. 在任何实际数据传输之前,两个节点都参与经过身份验证的密钥协商握手,该握手基于 Noise 协议框架<sup>2</sup>。
  2. 如果初始握手成功,则节点进入闪电网络消息交换阶段。在闪电网络消息交换阶段,所有消息都是带有相关数据的认证加密(AEAD)密文。

认证密钥协商握手

为身份验证的密钥交换选择的握手是 Noise_XK。作为预消息 (pre-message),发起者必须知道响应者的身份公钥。这为响应者提供了一定程度的身份隐藏,因为其静态公钥在握手期间从不传输。作为替代,身份验证是通过一系列椭圆曲线 Diffie-Hellman(ECDH)运算,然后进行 MAC 检查来隐式实现的。

经过身份验证的密钥协商(Noise_XK)分三个不同的步骤(行为)执行。在握手的每个行为中,都会发生以下情况:一些(可能已加密的)密钥材料被发送到另一方;执行 ECDH,具体取决于正在执行的行为,其结果混合到当前的一组加密密钥中(ck 链接密钥和 k 加密密钥);并发送带有零长度密文的 AEAD 有效负载。由于此有效负载没有长度,因此仅通过 MAC。将 ECDH 输出混合到哈希摘要中会形成增量 TripleDH 握手。

使用 Noise 协议的语言,es(都是公钥,其中 e 是临时密钥,s 是静态密钥,在我们的例子中通常是 nodeid)表示可能加密的密钥材料,eseese 各自表示两个密钥之间的 ECDH 运算。握手布局如下:

    Noise_XK(s, rs):
       &lt;- s
       ...
       -> e, es
       &lt;- e, ee
       -> s, se

在线传输的所有握手数据(包括密钥材料)都以增量方式哈希到会话范围的“握手摘要”h 中。请注意,握手状态 h 在握手期间永远不会传输;而是将摘要用作零长度 AEAD 消息中的关联数据。

验证发送的每条消息可确保中间人(MITM)没有修改或替换作为握手一部分发送的任何数据,因为在这种情况下,另一端的 MAC 检查将会失败。

接收者成功检查 MAC 隐含地表明到目前为止所有身份验证都已成功。如果在握手过程中 MAC 检查失败,则应立即终止连接。

握手版本控制

在初始握手期间发送的每条消息都以单个前导字节开头,该字节指示当前握手使用的版本。版本 0 表示不需要任何更改,而非零版本表示客户端已偏离本文档最初指定的协议。

客户端必须拒绝使用未知版本发起的握手尝试。

Noise 协议实例化

Noise 协议的具体实例化需要定义三个抽象密码对象:哈希函数、椭圆曲线和 AEAD 密码方案。对于闪电网络,选择 SHA-256 作为哈希函数,secp256k1 作为椭圆曲线,ChaChaPoly-1305 作为 AEAD 构造。

使用的 ChaCha20Poly1305 的组合必须符合 RFC 8439<sup>1</sup>。

Noise 的闪电网络变体的官方协议名称为 Noise_XK_secp256k1_ChaChaPoly_SHA256。此值的 ASCII 字符串表示形式哈希为摘要,用于初始化起始握手状态。如果两个端点的协议名称不同,则握手过程会立即失败。

认证密钥交换握手规范

握手分三个行为进行,需要 1.5 个往返。每个握手都是固定大小的有效负载,没有任何标头或其他元数据附加。每个行为的确切大小如下:

  • 行为一:50 字节
  • 行为二:50 字节
  • 行为三:66 字节

握手状态

在整个握手过程中,每一方都维护以下变量:

  • ck链接密钥。此值为所有先前 ECDH 输出的累积哈希。在握手结束时,ck 用于派生闪电消息的加密密钥。

  • h握手哈希。此值为到目前为止在握手过程中发送和接收的所有握手数据的累积哈希。

  • temp_k1temp_k2temp_k3中间密钥。这些用于在每个握手消息的末尾加密和解密零长度 AEAD 有效负载。

  • e:一方的临时密钥对。对于每个会话,节点必须使用强大的密码学随机性生成新的临时密钥。

  • s:一方的静态密钥对ls 用于本地,rs 用于远程)

还将引用以下函数:

  • ECDH(k, rk):使用 k(这是一个有效的 secp256k1 私钥)和 rk(这是一个有效的公钥)执行椭圆曲线 Diffie-Hellman 运算

    • 返回值为生成的点的压缩格式的 SHA256。
  • HKDF(salt,ikm)RFC 5869<sup>3</sup> 中定义的函数,使用零长度 info 字段进行评估

    • 所有 HKDF 的调用都隐式返回 64 字节的密码学随机性,使用 HKDF 的提取和扩展组件。
  • encryptWithAD(k, n, ad, plaintext):输出 encrypt(k, n, ad, plaintext)

    • 其中 encryptChaCha20-Poly1305(IETF 变体)的评估,带有传递的参数,nonce n 编码为 32 个零位,后跟一个小端64 位值。注意:这遵循 Noise 协议的约定,而不是我们通常使用的大端。
  • decryptWithAD(k, n, ad, ciphertext):输出 decrypt(k, n, ad, ciphertext)

    • 其中 decryptChaCha20-Poly1305(IETF 变体)的评估,带有传递的参数,nonce n 编码为 32 个零位,后跟一个小端64 位值。
  • generateKey():生成并返回一个新的 secp256k1 密钥对

    • 其中 generateKey 返回的对象具有两个属性:
      • .pub,它返回一个表示公钥的抽象对象
      • .priv,它表示用于生成公钥的私钥
    • 其中该对象还具有一个方法:
      • .serializeCompressed()
  • a || b 表示两个字节字符串 ab 的连接

握手状态初始化

在第一步开始之前,双方都按如下方式初始化其每个会话的状态:

  1. h = SHA-256(protocolName)

    • 其中 protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256" 编码为 ASCII 字符串
  2. ck = h

  3. h = SHA-256(h || prologue)

    • 其中 prologue 是 ASCII 字符串:lightning

作为最后一步,双方都将响应者的公钥混合到握手摘要中:

  • 发起节点混合响应节点的静态公钥,该公钥以比特币的压缩格式进行序列化:

    • h = SHA-256(h || rs.pub.serializeCompressed())
  • 响应节点混合其本地静态公钥,该公钥以比特币的压缩格式进行序列化:

    • h = SHA-256(h || ls.pub.serializeCompressed())

握手交换

行为一
    -> e, es

行为一从发起者发送到响应者。在行为一期间,发起者尝试满足响应者的隐式挑战。为了完成此挑战,发起者必须知道响应者的静态公钥。

握手消息正好是 50 个字节:1 个字节用于握手版本,33 个字节用于发起者的压缩临时公钥,16 个字节用于 poly1305 标签。

发送者操作:

  1. e = generateKey()
  2. h = SHA-256(h || e.pub.serializeCompressed())
    • 新生成的临时密钥会累积到正在运行的握手摘要中。
  3. es = ECDH(e.priv, rs)
    • 发起者在其新生成的临时密钥和远程节点的静态公钥之间执行 ECDH。
  4. ck, temp_k1 = HKDF(ck, es)
    • 生成一个新的临时加密密钥,该密钥用于生成身份验证 MAC。
  5. c = encryptWithAD(temp_k1, 0, h, zero)
    • 其中 zero 是零长度明文
  6. h = SHA-256(h || c)
    • 最后,生成的密文累积到身份验证的握手摘要中。
  7. 通过网络缓冲区将 m = 0 || e.pub.serializeCompressed() || c 发送到响应者。

接收者操作:

  1. 从网络缓冲区读取正好 50 个字节。
  2. 将读取的消息(m)解析为 vrec
    • 其中 vm第一个字节,rem 的接下来的 33 个字节,cm 的最后 16 个字节
    • 远程方的临时公钥(re)的原始字节将被反序列化为曲线上的点,使用密钥的序列化组成格式编码的仿射坐标。
  3. 如果 v 是无法识别的握手版本,则响应者必须中止连接尝试。
  4. h = SHA-256(h || re.serializeCompressed())
    • 响应者将发起者的临时密钥累积到身份验证握手摘要中。
  5. es = ECDH(s.priv, re)
    • 响应者在其静态私钥和发起者的临时公钥之间执行 ECDH。
  6. ck, temp_k1 = HKDF(ck, es)
    • 生成一个新的临时加密密钥,该密钥将很快用于检查身份验证 MAC。
  7. p = decryptWithAD(temp_k1, 0, h, c)
    • 如果此操作中的 MAC 检查失败,则发起者知道响应者的静态公钥。 如果是这种情况,则响应者必须在没有任何其他消息的情况下终止连接。
  8. h = SHA-256(h || c)
    • 接收到的密文混合到握手摘要中。此步骤用于确保有效负载未被 MITM 修改。
行为二
   &lt;- e, ee

行为二从响应者发送到发起者。只有在行为一成功的情况下,才会执行行为二。如果响应者能够正确解密并检查在行为一结束时发送的标签的 MAC,则行为一成功。

握手正好是 50 个字节:1 个字节用于握手版本,33 个字节用于响应者的压缩临时公钥,16 个字节用于 poly1305 标签。

发送者操作:

  1. e = generateKey()
  2. h = SHA-256(h || e.pub.serializeCompressed())
    • 新生成的临时密钥会累积到正在运行的握手摘要中。
  3. ee = ECDH(e.priv, re)
    • 其中 re 是发起者的临时密钥,该密钥已在行为一期间接收
  4. ck, temp_k2 = HKDF(ck, ee)
    • 生成一个新的临时加密密钥,该密钥用于生成身份验证 MAC。
  5. c = encryptWithAD(temp_k2, 0, h, zero)
    • 其中 zero 是零长度明文
  6. h = SHA-256(h || c)
    • 最后,生成的密文累积到身份验证的握手摘要中。
  7. 通过网络缓冲区将 m = 0 || e.pub.serializeCompressed() || c 发送到发起者。

接收者操作:

  1. 从网络缓冲区读取正好 50 个字节。
  2. 将读取的消息(m)解析为 vrec
    • 其中 vm第一个字节,rem 的接下来的 33 个字节,cm 的最后 16 个字节。
  3. 如果 v 是无法识别的握手版本,则响应者必须中止连接尝试。
  4. h = SHA-256(h || re.serializeCompressed())
  5. ee = ECDH(e.priv, re)
    • 其中 re 是响应者的临时公钥
    • 远程方的临时公钥(re)的原始字节将被反序列化为曲线上的点,使用密钥的序列化组成格式编码的仿射坐标。
  6. ck, temp_k2 = HKDF(ck, ee)
    • 生成一个新的临时加密密钥,该密钥用于生成身份验证 MAC。
  7. p = decryptWithAD(temp_k2, 0, h, c)
    • 如果此操作中的 MAC 检查失败,则发起者必须在没有任何其他消息的情况下终止连接。
  8. h = SHA-256(h || c)
    • 接收到的密文混合到握手摘要中。此步骤用于确保有效负载未被 MITM 修改。
行为三
   -> s, se

行为三是本节中描述的身份验证密钥协商的最后阶段。作为结论性步骤,此行为从发起者发送到响应者。当且仅当行为二成功时,才执行行为三。在行为三期间,发起者使用在握手的这一点上累积的 HKDF 派生的密钥,以前向保密性加密将其静态公钥传输给响应者。

握手正好是 66 个字节:1 个字节用于握手版本,33 个字节用于用 ChaCha20 流密码加密的静态公钥,16 个字节用于通过 AEAD 构造生成的加密公钥标签,以及 16 个字节用于最终的身份验证标签。

发送者操作:

  1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())
    • 其中 s 是发起者的静态公钥
  2. h = SHA-256(h || c)
  3. se = ECDH(s.priv, re)
    • 其中 re 是响应者的临时公钥
  4. ck, temp_k3 = HKDF(ck, se)
    • 最终的中间共享密钥混合到正在运行的链接密钥中。
  5. t = encryptWithAD(temp_k3, 0, h, zero)
    • 其中 zero 是零长度明文
  6. sk, rk = HKDF(ck, zero)
    • 其中 zero 是零长度明文, sk 是发起者用于加密发送给响应者的消息的密钥, rk 是发起者用于解密响应者发送的消息的密钥
    • 生成最终的加密密钥,用于在会话期间发送和接收消息。
  7. rn = 0, sn = 0
    • 发送和接收 nonce 初始化为 0。
  8. rck = sck = ck
    • 发送和接收链接密钥初始化为相同。
  9. 通过网络缓冲区发送 m = 0 || c || t

接收者操作:

  1. 从网络缓冲区读取正好 66 个字节。
  2. 将读取的消息(m)解析为 vct
    • 其中 vm第一个字节,cm 的接下来的 49 个字节,tm 的最后 16 个字节
  3. 如果 v 是无法识别的握手版本,则响应者必须中止连接尝试。
  4. rs = decryptWithAD(temp_k2, 1, h, c)
    • 至此,响应者已恢复了发起者的静态公钥。
    • 如果此操作中的 MAC 检查失败,则响应者必须在没有任何其他消息的情况下终止连接。
  5. h = SHA-256(h || c)
  6. se = ECDH(e.priv, rs)
    • 其中 e 是响应者的原始临时密钥
  7. ck, temp_k3 = HKDF(ck, se)
  8. p = decryptWithAD(temp_k3, 0, h, t)
    • 如果此操作中的 MAC 检查失败,则响应者必须在没有任何其他消息的情况下终止连接。
  9. rk, sk = HKDF(ck, zero)
    • 其中 zero 是零长度明文, rk 是响应者用于解密发起者发送的消息的密钥, sk 是响应者用于加密发送给发起者的消息的密钥
    • 生成最终的加密密钥,用于在会话期间发送和接收消息。
  10. rn = 0, sn = 0
    • 发送和接收 nonce 初始化为 0。
  11. rck = sck = ck
    • 发送和接收链接密钥初始化为相同。

闪电消息规范

在行为三结束时,双方都派生了加密密钥,这将用于加密和解密会话剩余时间内的消息。

实际的闪电网络协议消息封装在 AEAD 密文中。每个消息都以另一个 AEAD 密文为前缀,该密文对以下闪电网络消息的总长度进行编码(不包括其 MAC)。

任何闪电网络消息的最大大小不得超过 65535 个字节。65535 的最大大小简化了测试,使内存管理更加容易,并有助于缓解内存耗尽攻击。

为了使流量分析更加困难,所有加密的闪电网络消息的长度前缀也被加密。此外,将添加 16 字节的 Poly-1305 标签到加密的长度前缀,以确保数据包长度在传输过程中未被修改,并避免创建解密预言机。

在线传输的数据包的结构类似于以下内容:

+-------------------------------
|2-byte encrypted message length|  // 2 字节的加密消息长度
+-------------------------------
|  16-byte MAC of the encrypted |  // 加密消息长度的 16 字节 MAC
|        message length         |
+-------------------------------
|                               |
|                               |
|     encrypted Lightning       |  // 加密的闪电网络消息
|            message            |
|                               |
+-------------------------------
|     16-byte MAC of the        |  // 闪电网络消息的 16 字节 MAC
|      Lightning message        |
+-------------------------------

前缀消息长度编码为 2 字节大端整数,总最大数据包长度为 2 + 16 + 65535 + 16 = 65569 字节。

加密和发送消息

为了将闪电网络消息(m)加密并发送到网络流,给定一个发送密钥(sk)和一个 nonce(sn),完成以下步骤:

  1. l = len(m)
    • 其中 len 获取闪电网络消息的字节长度
  2. l 序列化为编码为大端整数的 2 个字节。
  3. 加密 l(使用 ChaChaPoly-1305snsk),以获得 lc(18 个字节)
    • nonce sn 编码为 96 位小端数字。由于解码的 nonce 为 64 位,因此 96 位 nonce 编码为:前面 32 位为 0,后跟 64 位值。
      • 在此步骤之后必须递增 nonce sn
    • 将零长度字节切片作为 AD(关联数据)传递。
  4. 最后,使用用于加密长度前缀的相同过程加密消息本身(m)。令加密的密文称为 c
    • 在此步骤之后必须递增 nonce sn
  5. 通过网络缓冲区发送 lc || c

接收和解密消息

为了解密网络流中的下一个消息,完成以下步骤:

  1. 从网络缓冲区读取正好 18 个字节。
  2. 令加密的长度前缀称为 lc
  3. 解密 lc(使用 ChaCha20-Poly1305rnrk),以获得加密数据包 l 的大小。
    • 将零长度字节切片作为 AD(关联数据)传递。
    • 在此步骤之后必须递增 nonce rn
  4. 从网络缓冲区读取正好 l+16 个字节,并将这些字节称为 c
  5. 解密 c(使用 ChaCha20-Poly1305rnrk),以获得解密的明文数据包 p
    • 在此步骤之后必须递增 nonce rn

闪电消息密钥轮换

定期更改密钥并忘记以前的密钥对于防止以后泄漏密钥(即后向保密)时解密旧消息很有用。

使用 sckrck 分别为每个密钥(skrk单独执行密钥轮换。在一方使用密钥加密或解密 1000 次后(即每 500 条消息)旋转密钥。可以通过在专用于它的 nonce 达到 1000 时旋转密钥来正确解决此问题。

密钥 k 的密钥轮换按照以下步骤执行:

  1. ck 为链接密钥(即 rkrcksksck
  2. ck', k' = HKDF(ck, k)
  3. 将密钥的 nonce 重置为 n = 0
  4. k = k'
  5. ck = ck'

安全注意事项

强烈建议对加密和解密使用现有的、常用的、经过验证的库,以避免许多可能的实现陷阱。

附录 A:传输测试向量

为了进行可重复的测试握手,以下指定了 generateKey() 将为每一方返回的值(即 e.priv 的值)。请注意,这违反了规范,该规范要求随机性。

发起者测试

当提供此输入时,发起者应该产生给定的输出。注释反映了内部状态,用于调试目的。

    name: transport-initiator successful handshake
    rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    # Act One
    # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
    # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
    # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
    # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
    # encryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, &lt;empty>)
    # c=0df6086551151f58b8afe6c195782c6a
    # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
    output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    # re=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
    # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
    # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
    # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
    # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, 0x6e2470b93aac583c9ef6eafca3f730ae)
    # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
    # Act Three
    # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa)
    # c=0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822
    # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
    # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
    # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
    # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
    # encryptWithAD(0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520, 0x000000000000000000000000, 0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660, &lt;empty>)
    # t=0x8dc68b1c466263b47fdf31e560e139ba
    output: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    # HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,zero)
    output: sk,rk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9,0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442

    name: transport-initiator act2 short read test
    rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730
    output: ERROR (ACT2_READ_FAILED)

    name: transport-initiator act2 bad version test
    rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    input: 0x0102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    output: ERROR (ACT2_BAD_VERSION 1)

    name: transport-initiator act2 bad key serialization test
    rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    input: 0x0004466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    output: ERROR (ACT2_BAD_PUBKEY)

    name: transport-initiator act2 bad MAC test
    rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730af
    output: ERROR (ACT2_BAD_TAG)

Responder Tests

responder 在收到此输入时,应该 产生给定的输出。

    name: transport-responder successful handshake
    ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    # Act One
    input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # re=0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
    # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
    # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
    # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
    # decryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, 0x0df6086551151f58b8afe6c195782c6a)
    # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
    # Act Two
    # e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27 e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
    # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
    # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
    # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
    # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, &lt;empty>)
    # c=0x6e2470b93aac583c9ef6eafca3f730ae
    # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
    output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    # Act Three
    input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822)
    # rs=0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
    # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
    # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
    # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
    # decryptWithAD(0x98```
name: transport-responder act3 错误的 MAC 用于密文测试
    ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    # Act One
    input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    # Act Three
    input: 0x00c9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    output: ERROR (ACT3_BAD_CIPHERTEXT)

    name: transport-responder act3 错误的 rs 测试
    ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    # Act One
    input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    # Act Three
    input: 0x00bfe3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa2235536ad09a8ee351870c2bb7f78b754a26c6cef79a98d25139c856d7efd252c2ae73c
    # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000001, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0xd7fedc211450dd9602b41081c9bd05328b8bf8c0238880f7b7cb8a34bb6d8354081e8d4b81887fae47a74fe8aab3008653)
    # rs=0x044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    output: ERROR (ACT3_BAD_PUBKEY)

    name: transport-responder act3 错误的 MAC 测试
    ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    # Act One
    input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    # Act Two
    output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    # Act Three
    input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139bb
    output: ERROR (ACT3_BAD_TAG)
### 消息加密测试

在这个测试中,发起者发送长度为 5 的消息,其中包含 "hello" 1001 次。为了简洁和测试两次密钥轮换,只显示了六个示例输出:

    name: transport-message 测试
    ck=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01
    sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9
    rk=0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
    # encrypt l: cleartext=0x0005, AD=NULL, sn=0x000000000000000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0xcf2b30ddf0cf3f80e7c35a6e6730b59fe802
    # encrypt m: cleartext=0x68656c6c6f, AD=NULL, sn=0x000000000100000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95
    output 0: 0xcf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95
    # encrypt l: cleartext=0x0005, AD=NULL, sn=0x000000000200000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x72887022101f0b6753e0c7de21657d35a4cb
    # encrypt m: cleartext=0x68656c6c6f, AD=NULL, sn=0x000000000300000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1
    output 1: 0x72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1
    # 0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8 = HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01, 0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9)
    # 0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8 = HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01, 0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9)
    output 500: 0x178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8
    output 501: 0x1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd
    # 0x728366ed68565dc17cf6dd97330a859a6a56e87e2beef3bd828a4c4a54d8df06, 0x9e0477f9850dca41e42db0e4d154e3a098e5a000d995e421849fcd5df27882bd = HKDF(0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8)
    # 0x728366ed68565dc17cf6dd97330a859a6a56e87e2beef3bd828a4c4a54d8df06, 0x9e0477f9850dca41e42db0e4d154e3a098e5a000d995e421849fcd5df27882bd = HKDF(0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8)
    output 1000: 0x4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09
    output 1001: 0x2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36

## 致谢

TODO(roasbeef);

## 参考文献
1. &lt;a id="reference-1">https://tools.ietf.org/html/rfc8439&lt;/a>
2. &lt;a id="reference-2">http://noiseprotocol.org/noise.html&lt;/a>
3. &lt;a id="reference-3">https://tools.ietf.org/html/rfc5869&lt;/a>

## 作者

FIXME

![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png "License CC-BY")
&lt;br>
本作品采用 [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/) 授权。
  • 原文链接: github.com/lightning/bol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
lightning
lightning
江湖只有他的大名,没有他的介绍。