本文档是闪电网络BOLT 8规范,详细描述了闪电网络节点之间加密和认证的传输协议。该协议使用Noise_XK握手进行密钥交换,并通过ChaChaPoly-1305算法加密所有通信数据,以保证节点间通信的保密性和完整性,同时包含了握手过程、消息加密、密钥轮换以及安全考虑等多个方面的内容。
闪电网络节点之间的所有通信都经过加密,以便为节点之间的所有记录提供保密性,并且经过身份验证以避免恶意干扰。每个节点都有一个已知的长期标识符,它是比特币 secp256k1
曲线上的公钥。这个长期公钥在协议中用于建立与对等点的加密和认证的连接,并且可以认证代表节点发布的任何信息。
在发送任何闪电网络消息之前,节点必须首先启动密码会话状态,该状态用于加密和验证节点之间发送的所有消息。此密码会话状态的初始化完全独立于任何内部协议消息头或约定。
两个节点之间的记录分为两个不同的部分:
为身份验证的密钥交换选择的握手是 Noise_XK
。作为预消息 (pre-message),发起者必须知道响应者的身份公钥。这为响应者提供了一定程度的身份隐藏,因为其静态公钥在握手期间从不传输。作为替代,身份验证是通过一系列椭圆曲线 Diffie-Hellman(ECDH)运算,然后进行 MAC 检查来隐式实现的。
经过身份验证的密钥协商(Noise_XK
)分三个不同的步骤(行为)执行。在握手的每个行为中,都会发生以下情况:一些(可能已加密的)密钥材料被发送到另一方;执行 ECDH,具体取决于正在执行的行为,其结果混合到当前的一组加密密钥中(ck
链接密钥和 k
加密密钥);并发送带有零长度密文的 AEAD 有效负载。由于此有效负载没有长度,因此仅通过 MAC。将 ECDH 输出混合到哈希摘要中会形成增量 TripleDH 握手。
使用 Noise 协议的语言,e
和 s
(都是公钥,其中 e
是临时密钥,s
是静态密钥,在我们的例子中通常是 nodeid
)表示可能加密的密钥材料,es
,ee
和 se
各自表示两个密钥之间的 ECDH 运算。握手布局如下:
Noise_XK(s, rs):
<- s
...
-> e, es
<- e, ee
-> s, se
在线传输的所有握手数据(包括密钥材料)都以增量方式哈希到会话范围的“握手摘要”h
中。请注意,握手状态 h
在握手期间永远不会传输;而是将摘要用作零长度 AEAD 消息中的关联数据。
验证发送的每条消息可确保中间人(MITM)没有修改或替换作为握手一部分发送的任何数据,因为在这种情况下,另一端的 MAC 检查将会失败。
接收者成功检查 MAC 隐含地表明到目前为止所有身份验证都已成功。如果在握手过程中 MAC 检查失败,则应立即终止连接。
在初始握手期间发送的每条消息都以单个前导字节开头,该字节指示当前握手使用的版本。版本 0 表示不需要任何更改,而非零版本表示客户端已偏离本文档最初指定的协议。
客户端必须拒绝使用未知版本发起的握手尝试。
Noise 协议的具体实例化需要定义三个抽象密码对象:哈希函数、椭圆曲线和 AEAD 密码方案。对于闪电网络,选择 SHA-256
作为哈希函数,secp256k1
作为椭圆曲线,ChaChaPoly-1305
作为 AEAD 构造。
使用的 ChaCha20
和 Poly1305
的组合必须符合 RFC 8439
<sup>1</sup>。
Noise 的闪电网络变体的官方协议名称为 Noise_XK_secp256k1_ChaChaPoly_SHA256
。此值的 ASCII 字符串表示形式哈希为摘要,用于初始化起始握手状态。如果两个端点的协议名称不同,则握手过程会立即失败。
握手分三个行为进行,需要 1.5 个往返。每个握手都是固定大小的有效负载,没有任何标头或其他元数据附加。每个行为的确切大小如下:
在整个握手过程中,每一方都维护以下变量:
ck
:链接密钥。此值为所有先前 ECDH 输出的累积哈希。在握手结束时,ck
用于派生闪电消息的加密密钥。
h
:握手哈希。此值为到目前为止在握手过程中发送和接收的所有握手数据的累积哈希。
temp_k1
,temp_k2
,temp_k3
:中间密钥。这些用于在每个握手消息的末尾加密和解密零长度 AEAD 有效负载。
e
:一方的临时密钥对。对于每个会话,节点必须使用强大的密码学随机性生成新的临时密钥。
s
:一方的静态密钥对(ls
用于本地,rs
用于远程)
还将引用以下函数:
ECDH(k, rk)
:使用 k
(这是一个有效的 secp256k1
私钥)和 rk
(这是一个有效的公钥)执行椭圆曲线 Diffie-Hellman 运算
HKDF(salt,ikm)
:RFC 5869
<sup>3</sup> 中定义的函数,使用零长度 info
字段进行评估
HKDF
的调用都隐式返回 64 字节的密码学随机性,使用 HKDF
的提取和扩展组件。encryptWithAD(k, n, ad, plaintext)
:输出 encrypt(k, n, ad, plaintext)
encrypt
是 ChaCha20-Poly1305
(IETF 变体)的评估,带有传递的参数,nonce n
编码为 32 个零位,后跟一个小端64 位值。注意:这遵循 Noise 协议的约定,而不是我们通常使用的大端。decryptWithAD(k, n, ad, ciphertext)
:输出 decrypt(k, n, ad, ciphertext)
decrypt
是 ChaCha20-Poly1305
(IETF 变体)的评估,带有传递的参数,nonce n
编码为 32 个零位,后跟一个小端64 位值。generateKey()
:生成并返回一个新的 secp256k1
密钥对
generateKey
返回的对象具有两个属性:
.pub
,它返回一个表示公钥的抽象对象.priv
,它表示用于生成公钥的私钥.serializeCompressed()
a || b
表示两个字节字符串 a
和 b
的连接
在第一步开始之前,双方都按如下方式初始化其每个会话的状态:
h = SHA-256(protocolName)
protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"
编码为 ASCII 字符串ck = h
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
标签。
发送者操作:
e = generateKey()
h = SHA-256(h || e.pub.serializeCompressed())
es = ECDH(e.priv, rs)
ck, temp_k1 = HKDF(ck, es)
c = encryptWithAD(temp_k1, 0, h, zero)
zero
是零长度明文h = SHA-256(h || c)
m = 0 || e.pub.serializeCompressed() || c
发送到响应者。接收者操作:
m
)解析为 v
,re
和 c
:
v
是 m
的第一个字节,re
是 m
的接下来的 33 个字节,c
是 m
的最后 16 个字节re
)的原始字节将被反序列化为曲线上的点,使用密钥的序列化组成格式编码的仿射坐标。v
是无法识别的握手版本,则响应者必须中止连接尝试。h = SHA-256(h || re.serializeCompressed())
es = ECDH(s.priv, re)
ck, temp_k1 = HKDF(ck, es)
p = decryptWithAD(temp_k1, 0, h, c)
h = SHA-256(h || c)
<- e, ee
行为二从响应者发送到发起者。只有在行为一成功的情况下,才会执行行为二。如果响应者能够正确解密并检查在行为一结束时发送的标签的 MAC,则行为一成功。
握手正好是 50 个字节:1 个字节用于握手版本,33 个字节用于响应者的压缩临时公钥,16 个字节用于 poly1305
标签。
发送者操作:
e = generateKey()
h = SHA-256(h || e.pub.serializeCompressed())
ee = ECDH(e.priv, re)
re
是发起者的临时密钥,该密钥已在行为一期间接收ck, temp_k2 = HKDF(ck, ee)
c = encryptWithAD(temp_k2, 0, h, zero)
zero
是零长度明文h = SHA-256(h || c)
m = 0 || e.pub.serializeCompressed() || c
发送到发起者。接收者操作:
m
)解析为 v
,re
和 c
:
v
是 m
的第一个字节,re
是 m
的接下来的 33 个字节,c
是 m
的最后 16 个字节。v
是无法识别的握手版本,则响应者必须中止连接尝试。h = SHA-256(h || re.serializeCompressed())
ee = ECDH(e.priv, re)
re
是响应者的临时公钥re
)的原始字节将被反序列化为曲线上的点,使用密钥的序列化组成格式编码的仿射坐标。ck, temp_k2 = HKDF(ck, ee)
p = decryptWithAD(temp_k2, 0, h, c)
h = SHA-256(h || c)
-> s, se
行为三是本节中描述的身份验证密钥协商的最后阶段。作为结论性步骤,此行为从发起者发送到响应者。当且仅当行为二成功时,才执行行为三。在行为三期间,发起者使用在握手的这一点上累积的 HKDF
派生的密钥,以强前向保密性加密将其静态公钥传输给响应者。
握手正好是 66 个字节:1 个字节用于握手版本,33 个字节用于用 ChaCha20
流密码加密的静态公钥,16 个字节用于通过 AEAD 构造生成的加密公钥标签,以及 16 个字节用于最终的身份验证标签。
发送者操作:
c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())
s
是发起者的静态公钥h = SHA-256(h || c)
se = ECDH(s.priv, re)
re
是响应者的临时公钥ck, temp_k3 = HKDF(ck, se)
t = encryptWithAD(temp_k3, 0, h, zero)
zero
是零长度明文sk, rk = HKDF(ck, zero)
zero
是零长度明文,
sk
是发起者用于加密发送给响应者的消息的密钥,
rk
是发起者用于解密响应者发送的消息的密钥rn = 0, sn = 0
rck = sck = ck
m = 0 || c || t
。接收者操作:
m
)解析为 v
,c
和 t
:
v
是 m
的第一个字节,c
是 m
的接下来的 49 个字节,t
是 m
的最后 16 个字节v
是无法识别的握手版本,则响应者必须中止连接尝试。rs = decryptWithAD(temp_k2, 1, h, c)
h = SHA-256(h || c)
se = ECDH(e.priv, rs)
e
是响应者的原始临时密钥ck, temp_k3 = HKDF(ck, se)
p = decryptWithAD(temp_k3, 0, h, t)
rk, sk = HKDF(ck, zero)
zero
是零长度明文,
rk
是响应者用于解密发起者发送的消息的密钥,
sk
是响应者用于加密发送给发起者的消息的密钥rn = 0, sn = 0
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
),完成以下步骤:
l = len(m)
。
len
获取闪电网络消息的字节长度l
序列化为编码为大端整数的 2 个字节。l
(使用 ChaChaPoly-1305
,sn
和 sk
),以获得 lc
(18 个字节)
sn
编码为 96 位小端数字。由于解码的 nonce 为 64 位,因此 96 位 nonce 编码为:前面 32 位为 0,后跟 64 位值。
sn
。m
)。令加密的密文称为 c
。
sn
。lc || c
。为了解密网络流中的下一个消息,完成以下步骤:
lc
。lc
(使用 ChaCha20-Poly1305
,rn
和 rk
),以获得加密数据包 l
的大小。
rn
。l+16
个字节,并将这些字节称为 c
。c
(使用 ChaCha20-Poly1305
,rn
和 rk
),以获得解密的明文数据包 p
。
rn
。定期更改密钥并忘记以前的密钥对于防止以后泄漏密钥(即后向保密)时解密旧消息很有用。
使用 sck
和 rck
分别为每个密钥(sk
和 rk
)单独执行密钥轮换。在一方使用密钥加密或解密 1000 次后(即每 500 条消息)旋转密钥。可以通过在专用于它的 nonce 达到 1000 时旋转密钥来正确解决此问题。
密钥 k
的密钥轮换按照以下步骤执行:
ck
为链接密钥(即 rk
的 rck
或 sk
的 sck
)ck', k' = HKDF(ck, k)
n = 0
。k = k'
ck = ck'
强烈建议对加密和解密使用现有的、常用的、经过验证的库,以避免许多可能的实现陷阱。
为了进行可重复的测试握手,以下指定了 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, <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, <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 在收到此输入时,应该 产生给定的输出。
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, <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. <a id="reference-1">https://tools.ietf.org/html/rfc8439</a>
2. <a id="reference-2">http://noiseprotocol.org/noise.html</a>
3. <a id="reference-3">https://tools.ietf.org/html/rfc5869</a>
## 作者
FIXME

<br>
本作品采用 [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/) 授权。
- 原文链接: github.com/lightning/bol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!