此翻译是使用机器学习生成的,可能不是100%准确。 查看英文版本

新的 netDB 条目

Proposal 123
打开
Author zzz, str4d, orignal
Created 2016-01-16
Last Updated 2020-07-18
Supercedes: 110, 120, 121, 122

状态

本提案的部分内容已完成,并已在 0.9.38 和 0.9.39 版本中实现。
通用结构、I2CP、I2NP 及其他规范
现已更新,以反映当前支持的变更。

已完成的部分仍可能进行小幅修订。
本提案的其他部分仍在开发中,
并可能进行重大修订。

服务查找(类型 9 和 11)优先级较低,
尚未排期,可能会拆分为单独的提案。

概述

这是以下 4 个提案的更新与整合:

  • 110 LS2
  • 120 用于大规模多宿主的元 LS2(Meta LS2)
  • 121 加密 LS2
  • 122 无认证服务查找(任播)

这些提案大多是独立的,但为了逻辑清晰,我们为其中多个定义并使用了
通用格式。

以下提案与此相关:

  • 140 隐式多宿主(与本提案不兼容)
  • 142 新加密模板(用于新对称加密)
  • 144 ECIES-X25519-AEAD-Ratchet
  • 145 ECIES-P256
  • 146 Red25519
  • 148 EdDSA-BLAKE2b-Ed25519
  • 149 B32 用于加密 LS2
  • 150 Garlic Farm 协议
  • 151 ECDSA Blinding

提案

本提案定义了 5 种新的 DatabaseEntry 类型,以及
将它们存储到网络数据库和从中检索的方法,
还包括签名和验证签名的方法。

目标

  • 向后兼容
  • LS2 可与旧式多宿主共用
  • 支持无需新加密或原语
  • 保持加密与签名的解耦;支持所有当前和未来版本
  • 支持可选的离线签名密钥
  • 降低时间戳精度以减少指纹识别
  • 支持目的地使用新加密
  • 支持大规模多宿主
  • 修复现有加密 LS 的多个问题
  • 可选的盲化以减少 floodfill 的可见性
  • 加密支持单密钥和多个可撤销密钥
  • 服务查找以简化 outproxy、应用 DHT 引导等查找
  • 不破坏依赖 32 字节二进制目的地哈希的任何功能,例如 bittorrent
  • 通过属性增加 leasesets 的灵活性,类似 routerinfos 中的机制
  • 将发布时间戳和可变过期时间放入头部,以便即使内容被加密也能工作(不从最早租约推导时间戳)
  • 所有新类型与现有 leasesets 位于相同的 DHT 空间和位置,
    使用户可从旧 LS 迁移到 LS2,
    或在 LS2、Meta 和加密之间切换,
    而无需更改 Destination 或哈希。
  • 现有 Destination 可转换为使用离线密钥,
    或恢复为在线密钥,而无需更改 Destination 或哈希。

非目标 / 范围外

  • 新的 DHT 轮转算法或共享随机数生成
  • 具体的新加密类型和使用该类型进行端到端加密的方案
    将在单独的提案中说明。
    本文不指定或讨论任何新加密。
  • RI 或隧道构建的新加密。
    这将在单独的提案中说明。
  • I2NP DLM / DSM / DSRM 消息的加密、传输和接收方法。
    不作更改。
  • 如何生成和管理 Meta,包括后端路由器间通信、管理、故障转移和协调。
    可能会添加到 I2CP、i2pcontrol 或新协议中。
    这可能不会被标准化。
  • 如何实际实现和管理长期存在的隧道,或取消现有隧道。
    这极其困难,没有它就无法实现合理的优雅关闭。
  • 威胁模型变更
  • 离线存储格式,或存储/检索/共享数据的方法。
  • 实现细节不在本文讨论范围内,由各项目自行决定。

理由

LS2 添加了用于更改加密类型和未来协议变更的字段。

加密 LS2 通过使用非对称加密整个租约集,
修复了现有加密 LS 的多个安全问题。

Meta LS2 提供了灵活、高效、有效且大规模的多宿主。

服务记录(Service Record)和服务列表(Service List)提供任播服务,如命名查找和 DHT 引导。

NetDB 数据类型

类型编号用于 I2NP 数据库查找/存储消息中。

“端到端”列指查询/响应是否作为大蒜消息发送到 Destination。

现有类型:

NetDB 数据查找类型存储类型
any0any
LS11
RI20
exploratory3DSRM

新类型:

NetDB 数据查找类型存储类型标准 LS2 头?端到端发送?
LS213yesyes
加密 LS215nono
Meta LS217yesno
服务记录n/a9yesno
服务列表411nono

说明

  • 查找类型目前使用数据库查找消息中的位 3-2。
    任何额外类型都需要使用位 4。

  • 所有存储类型均为奇数,因为旧路由器会忽略数据库存储消息
    类型字段的高位。
    我们宁愿让解析失败为 LS 而不是压缩的 RI。

  • 类型应在签名覆盖的数据中显式、隐式还是都不包含?

查找/存储流程

类型 3、5 和 7 可作为标准 leaseset 查找(类型 1)的响应返回。
类型 9 永远不会作为查找的响应返回。
类型 11 作为新的服务查找类型(类型 11)的响应返回。

只有类型 3 可在客户端到客户端的大蒜消息中发送。

格式

类型 3、7 和 9 具有通用格式::

标准 LS2 头

  • 如下定义

类型特定部分

  • 如下各部分中定义

标准 LS2 签名:

  • 长度由签名密钥的签名类型隐含

类型 5(加密)不以 Destination 开头,具有
不同格式。见下文。

类型 11(服务列表)是多个服务记录的聚合,具有
不同格式。见下文。

隐私/安全考虑

待定

标准 LS2 头

类型 3、7 和 9 使用标准 LS2 头,如下指定:

格式

标准 LS2 头:
  - 类型 (1 字节)
    实际上不在头中,但属于签名覆盖的数据。
    从数据库存储消息的字段中获取。
  - 目的地 (387+ 字节)
  - 发布时间戳 (4 字节,大端序,自纪元以来的秒数,2106 年回绕)
  - 过期 (2 字节,大端序) (自发布时间戳起的秒数偏移,最大 18.2 小时)
  - 标志 (2 字节)
    位顺序:15 14 ... 3 2 1 0
    位 0:0 表示无离线密钥;1 表示有离线密钥
    位 1:0 表示标准已发布 leaseset;
           1 表示未发布 leaseset。不应被泛洪、发布或
           作为查询响应发送。如果此 leaseset 过期,除非设置了位 2,否则不要查询
           netdb 获取新的。
    位 2:0 表示标准已发布 leaseset;
           1 表示此未加密 leaseset 发布时将被盲化和加密。
           如果此 leaseset 过期,查询 netdb 中的盲化位置以获取新的。
           如果此位设置为 1,也应将位 1 设置为 1。
           自 0.9.42 版本起。
    位 3-15:为兼容未来用途设为 0
  - 如果标志指示离线密钥,则包含离线签名部分:
    过期时间戳 (4 字节,大端序,自纪元以来的秒数,2106 年回绕)
    临时签名类型 (2 字节,大端序)
    临时签名公钥 (长度由签名类型隐含)
    由目的地公钥对过期时间戳、临时签名类型和公钥的签名,
    长度由目的地公钥签名类型隐含。
    此部分可以且应离线生成。

理由

  • 未发布/已发布:用于端到端发送数据库存储时,
    发送路由器可能希望指示此 leaseset 不应发送给他人。
    我们目前使用启发式方法维护此状态。

  • 已发布:取代了确定 leaseset “版本”所需的复杂逻辑。
    目前,版本是最后过期租约的过期时间,
    发布路由器在发布仅移除旧租约的 leaseset 时,
    必须至少增加 1ms。

  • 过期:允许 netdb 条目的过期时间早于其最后过期的 leaseset。
    对于 LS2 可能无用(预期 leaseset 保持 11 分钟最大过期),
    但对于其他新类型是必要的(见下文的 Meta LS 和服务记录)。

  • 离线密钥是可选的,以降低初始/必需实现的复杂性。

问题

  • 可进一步降低时间戳精度(10 分钟?)但需添加版本号。
    这可能会破坏多宿主,除非我们有保序加密?
    可能无法完全不用时间戳。

  • 替代方案:3 字节时间戳(纪元 / 10 分钟),1 字节版本,2 字节过期

  • 类型在数据/签名中是显式还是隐式?签名的“域”常量?

说明

  • 路由器不应每秒发布超过一次 LS。
    如果这样做,必须将发布时间戳人为增加 1
    超过之前发布的 LS。

  • 路由器实现可缓存临时密钥和签名,
    以避免每次验证。特别是 floodfill 和长期连接两端的路由器可从中受益。

  • 离线密钥和签名仅适用于长期存在的目的地,
    即服务器,而非客户端。

新 DatabaseEntry 类型

LeaseSet 2

与现有 LeaseSet 的变更:

  • 添加发布时间戳、过期时间戳、标志和属性
  • 添加加密类型
  • 移除撤销密钥

查找使用
标准 LS 标志 (1)
存储使用
标准 LS2 类型 (3)
存储于
目的地的哈希
此哈希随后用于生成每日“路由密钥”,如 LS1
典型过期时间
10 分钟,与常规 LS 相同

目的地发布

格式

如上所述的标准 LS2 头

  标准 LS2 类型特定部分
  - 属性 (如通用结构规范中指定的映射,若无则为 2 个零字节)
  - 后续密钥段数量 (1 字节,最大值待定)
  - 密钥段:
    - 加密类型 (2 字节,大端序)
    - 加密密钥长度 (2 字节,大端序)
      这是显式的,以便 floodfill 可解析未知加密类型的 LS2。
    - 加密密钥 (指定字节数)
  - lease2 数量 (1 字节)
  - Lease2s (每个 40 字节)
    这些是租约,但过期时间为 4 字节而非 8 字节,
    自纪元以来的秒数(2106 年回绕)

  标准 LS2 签名:
  - 签名
    如果标志指示离线密钥,则由临时公钥签名,
    否则由目的地公钥签名
    长度由签名密钥的签名类型隐含
    签名覆盖上述所有内容。

理由

  • 属性:未来扩展和灵活性。
    放在首位,以便必要时用于解析剩余数据。

  • 多个加密类型/公钥对
    有助于过渡到新加密类型。另一种方法是
    发布多个 leasesets,可能使用相同隧道,
    如我们现在对 DSA 和 EdDSA 目的地所做的那样。
    隧道中传入加密类型的识别
    可使用现有的会话标签机制,
    和/或使用每个密钥进行试解密。传入消息的长度也可能提供线索。

讨论

本提案继续使用 leaseset 中的公钥作为
端到端加密密钥,并保留目的地中的公钥字段未使用,如现在一样。
加密类型未在目的地密钥证书中指定,将保持为 0。

一个被拒绝的替代方案是在目的地密钥证书中指定加密类型,
使用目的地中的公钥,而不使用 leaseset 中的公钥。
我们不计划这样做。

LS2 的优点:

  • 实际公钥的位置不变。
  • 加密类型或公钥可在不更改目的地的情况下更改。
  • 移除了未使用的撤销字段
  • 与本提案中其他 DatabaseEntry 类型的基本兼容性
  • 允许多个加密类型

LS2 的缺点:

  • 公钥和加密类型的位置与 RouterInfo 不同
  • 在 leaseset 中保留了未使用的公钥
  • 需要全网实现;作为替代,实验性加密类型可使用,如果 floodfill 允许
    (但参见相关提案 136 和 137 关于支持实验性签名类型)。
    替代提案可能更容易为实验性加密类型实现和测试。

新加密问题

其中一些超出本提案范围,
但暂时在此记录,因为我们尚未有
单独的加密提案。
另见 ECIES 提案 144 和 145。

  • 加密类型代表曲线、密钥长度和端到端方案的组合,
    包括 KDF 和 MAC(如果有)。

  • 我们包含了密钥长度字段,以便 LS2
    即使对于未知加密类型,floodfill 也能解析和验证。

  • 第一个提议的新加密类型
    可能是 ECIES/X25519。其端到端使用方式
    (略微修改的 ElGamal/AES+SessionTag
    或完全新的,如 ChaCha/Poly)将在一个或多个单独提案中指定。
    另见 ECIES 提案 144 和 145。

说明

  • 租约中的 8 字节过期时间改为 4 字节。

  • 如果我们实现撤销,可通过设置过期字段为零,
    或零租约,或两者来实现。无需单独的撤销密钥。

  • 加密密钥按服务器偏好排序,最优先的在前。
    客户端默认行为是选择第一个支持的加密类型的密钥。
    客户端可基于加密支持、相对性能和其他因素使用其他选择算法。

加密 LS2

目标:

  • 添加盲化
  • 允许多个签名类型
  • 不需要任何新加密原语
  • 可选地加密给每个接收者,可撤销
  • 仅支持加密标准 LS2 和 Meta LS2

加密 LS2 永远不会在端到端大蒜消息中发送。
使用上述标准 LS2。

与现有加密 LeaseSet 的变更:

  • 为安全加密整个内容
  • 安全加密,不仅使用 AES。
  • 加密给每个接收者

查找使用
标准 LS 标志 (1)
存储使用
加密 LS2 类型 (5)
存储于
盲化签名类型和盲化公钥的哈希
两字节签名类型(大端序,例如 0x000b)|| 盲化公钥
此哈希随后用于生成每日“路由密钥”,如 LS1
典型过期时间
10 分钟,如常规 LS,或数小时,如 meta LS。

目的地发布

定义

我们定义以下函数,对应于用于加密 LS2 的加密构建块:

CSRNG(n)
密码学安全随机数生成器的 n 字节输出。

除了 CSRNG 需要密码学安全(因此适合生成密钥材料)的要求外,  
它必须安全,即使某些 n 字节输出用于密钥材料,  
而其前后字节序列暴露在网络上(如盐或加密填充)。  
依赖不可信源的实现应对暴露在网络上的任何输出进行哈希。  
参见 [PRNG references](http://projectbullrun.org/dual-ec/ext-rand.html) 和 [Tor dev discussion](https://lists.torproject.org/pipermail/tor-dev/2015-November/009954.html)。

H(p, d)
取个性化字符串 p 和数据 d 的 SHA-256 哈希函数,
产生 32 字节输出。

使用 SHA-256 如下::

    H(p, d) := SHA-256(p || d)

STREAM
RFC 7539 第 2.4 节 中指定的 ChaCha20 流密码,初始计数器
设为 1。S_KEY_LEN = 32 且 S_IV_LEN = 12。

ENCRYPT(k, iv, plaintext)  
    使用密钥 k 和必须对密钥 k 唯一的 nonce iv 加密明文。  
    返回与明文大小相同的密文。

    如果密钥保密,整个密文必须与随机数据无法区分。

DECRYPT(k, iv, ciphertext)  
    使用密钥 k 和 nonce iv 解密密文。返回明文。

SIG
带密钥盲化的 RedDSA 签名方案(对应签名类型 11)。
它具有以下函数:

DERIVE_PUBLIC(privkey)  
    返回与给定私钥对应的公钥。

SIGN(privkey, m)  
    返回私钥 privkey 对给定消息 m 的签名。

VERIFY(pubkey, m, sig)  
    验证签名 sig 对公钥 pubkey 和消息 m。如果签名有效返回 true,否则返回 false。

它还必须支持以下密钥盲化操作:

GENERATE_ALPHA(data, secret)  
    为知道 data 和可选 secret 的人生成 alpha。  
    结果必须与私钥具有相同的分布。

BLIND_PRIVKEY(privkey, alpha)  
    使用秘密 alpha 盲化私钥。

BLIND_PUBKEY(pubkey, alpha)  
    使用秘密 alpha 盲化公钥。  
    对于给定密钥对 (privkey, pubkey),以下关系成立::

        BLIND_PUBKEY(pubkey, alpha) ==
        DERIVE_PUBLIC(BLIND_PRIVKEY(privkey, alpha))

DH
X25519 公钥协商系统。私钥 32 字节,公钥 32 字节,产生 32 字节输出。它具有以下函数:

GENERATE_PRIVATE()  
    生成新私钥。

DERIVE_PUBLIC(privkey)  
    返回与给定私钥对应的公钥。

DH(privkey, pubkey)  
    从给定私钥和公钥生成共享密钥。

HKDF(salt, ikm, info, n)
密码学密钥派生函数,取一些输入密钥材料 ikm(应有良好熵但不要求是均匀随机字符串)、
32 字节长的 salt 和特定于上下文的 ‘info’ 值,产生 n 字节输出,适合用作密钥材料。

使用 [RFC 5869](https://tools.ietf.org/html/rfc5869) 中指定的 HKDF,使用 [RFC 2104](https://tools.ietf.org/html/rfc2104) 中指定的 HMAC 哈希函数 SHA-256。  
这意味着 SALT_LEN 最大为 32 字节。

格式

加密 LS2 格式由三层嵌套组成:

  • 外层包含存储和检索所需的必要明文信息。
  • 中间层处理客户端认证。
  • 内层包含实际的 LS2 数据。

整体格式如下::

第 0 层数据 + Enc(第 1 层数据 + Enc(第 2 层数据)) + 签名

注意加密 LS2 是盲化的。头中没有 Destination。
DHT 存储位置是 SHA-256(sig type || 盲化公钥),每日轮转。

不使用上述指定的标准 LS2 头。

第 0 层(外层)

类型
1 字节

实际上不在头中,但属于签名覆盖的数据。  
从数据库存储消息的字段中获取。

盲化公钥签名类型
2 字节,大端序
这将始终是类型 11,标识 Red25519 盲化密钥。

盲化公钥
长度由签名类型隐含

发布时间戳
4 字节,大端序

自纪元以来的秒数,2106 年回绕

过期
2 字节,大端序

自发布时间戳起的秒数偏移,最大 18.2 小时

标志
2 字节

位顺序:15 14 ... 3 2 1 0

位 0:0 表示无离线密钥;1 表示有离线密钥

其他位:为兼容未来用途设为 0

临时密钥数据
如果标志指示离线密钥则存在

过期时间戳  
    4 字节,大端序

    自纪元以来的秒数,2106 年回绕

临时签名类型  
    2 字节,大端序

临时签名公钥  
    长度由签名类型隐含

签名  
    长度由盲化公钥签名类型隐含

    对过期时间戳、临时签名类型和临时公钥的签名。

    使用盲化公钥验证。

lenOuterCiphertext
2 字节,大端序

outerCiphertext
lenOuterCiphertext 字节

加密的第 1 层数据。密钥派生和加密算法见下文。

签名
长度由所用签名密钥的签名类型隐含

对上述所有内容的签名。

如果标志指示离线密钥,签名使用临时公钥验证。  
否则,使用盲化公钥验证。

第 1 层(中间层)

标志
1 字节

位顺序:76543210

位 0:0 表示所有人,1 表示每个客户端,后续有认证部分

位 3-1:认证方案,仅当位 0 设为 1(每个客户端)时设置,否则为 000  
          000:DH 客户端认证(或无每个客户端认证)  
          001:PSK 客户端认证

位 7-4:未使用,为未来兼容性设为 0

DH 客户端认证数据
如果标志位 0 设为 1 且标志位 3-1 设为 000 则存在。

ephemeralPublicKey  
    32 字节

clients  
    2 字节,大端序

    后续 authClient 条目数量,每个 40 字节

authClient  
    单个客户端的授权数据。  
    每个客户端授权算法见下文。

    clientID_i  
        8 字节

    clientCookie_i  
        32 字节

PSK 客户端认证数据
如果标志位 0 设为 1 且标志位 3-1 设为 001 则存在。

authSalt  
    32 字节

clients  
    2 字节,大端序

    后续 authClient 条目数量,每个 40 字节

authClient  
    单个客户端的授权数据。  
    每个客户端授权算法见下文。

    clientID_i  
        8 字节

    clientCookie_i  
        32 字节

innerCiphertext
长度由 lenOuterCiphertext 隐含(剩余数据)

加密的第 2 层数据。密钥派生和加密算法见下文。

第 2 层(内层)

类型
1 字节

3(LS2)或 7(Meta LS2)

数据
给定类型的 LeaseSet2 数据。

包括头和签名。

盲化密钥派生

我们使用以下方案进行密钥盲化,
基于 Ed25519 和 ZCash RedDSA
Re25519 签名在 Ed25519 曲线上,使用 SHA-512 作为哈希。

我们不使用 Tor’s rend-spec-v3.txt appendix A.2
因为其盲化公钥可能不在素数阶子群中,安全影响未知。

目标

  • 未盲化目的地中的签名公钥必须是
    Ed25519(签名类型 7)或 Red25519(签名类型 11);
    不支持其他签名类型
  • 如果签名公钥是离线的,临时签名公钥也必须是 Ed25519
  • 盲化在计算上简单
  • 使用现有加密原语
  • 盲化公钥无法被反盲化
  • 盲化公钥必须在 Ed25519 曲线和素数阶子群上
  • 必须知道目的地的签名公钥
    (不需要完整目的地)以派生盲化公钥
  • 可选地提供派生盲化公钥所需的额外密钥

安全性

盲化方案的安全性要求 alpha 的分布与未盲化私钥相同。
然而,当我们盲化 Ed25519 私钥(签名类型 7)
到 Red25519 私钥(签名类型 11)时,分布不同。
为满足 zcash 第 4.1.6.1 节 的要求,
Red25519(签名类型 11)也应用于未盲化密钥,
以便“重新随机化的公钥和该密钥下的签名组合
不会泄露从中重新随机化的密钥”。
我们允许类型 7 用于现有目的地,但建议
新目的地使用类型 11。

定义

B
Ed25519 基点(生成元)2^255 - 19,如 Ed25519

L
Ed25519 阶 2^252 + 27742317777372353535851937790883648493
Ed25519

DERIVE_PUBLIC(a)
将私钥转换为公钥,如 Ed25519(乘以 G)

alpha
32 字节随机数,知道目的地的人知道。

GENERATE_ALPHA(destination, date, secret)
为当前日期生成 alpha,给知道目的地和密钥的人。
结果必须与 Ed25519 私钥具有相同的分布。

a
用于签名目的地的未盲化 32 字节 EdDSA 或 RedDSA 签名私钥

A
目的地中的未盲化 32 字节 EdDSA 或 RedDSA 签名公钥,
= DERIVE_PUBLIC(a),如 Ed25519

a’
用于签名加密 leaseset 的盲化 32 字节 EdDSA 签名私钥
这是有效的 EdDSA 私钥。

A’
目的地中的盲化 32 字节 EdDSA 签名公钥,
可通过 DERIVE_PUBLIC(a’) 或从 A 和 alpha 生成。
这是有效的 EdDSA 公钥,在曲线上且在素数阶子群上。

LEOS2IP(x)
将输入字节顺序翻转为小端序

H*(x)
32 字节 = (LEOS2IP(SHA512(x))) mod B,与 Ed25519 哈希和约减相同

盲化计算

每天(UTC)必须生成新的密钥 alpha 和盲化密钥。
密钥 alpha 和盲化密钥计算如下。

GENERATE_ALPHA(destination, date, secret),适用于所有方:

// GENERATE_ALPHA(destination, date, secret)

  // secret 是可选的,否则为空长度
  A = 目的地的签名公钥
  stA = A 的签名类型,2 字节大端序 (0x0007 或 0x000b)
  stA' = 盲化公钥 A' 的签名类型,2 字节大端序 (0x000b)
  keydata = A || stA || stA'
  datestring = 8 字节 ASCII YYYYMMDD,来自当前日期 UTC
  secret = UTF-8 编码字符串
  seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64)
  // 将 seed 视为 64 字节小端序值
  alpha = seed mod L

BLIND_PRIVKEY(),由发布 leaseset 的所有者使用:

// BLIND_PRIVKEY()

  alpha = GENERATE_ALPHA(destination, date, secret)
  // 如果是 Ed25519 私钥(类型 7)
  seed = 目的地的签名私钥
  a = SHA512(seed) 的左半部分,通常对 Ed25519 进行钳位
  // 否则,对于 Red25519 私钥(类型 11)
  a = 目的地的签名私钥
  // 使用标量算术加法
  盲化签名私钥 = a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
  盲化签名公钥 = A' = DERIVE_PUBLIC(a')

BLIND_PUBKEY(),由检索 leaseset 的客户端使用:

// BLIND_PUBKEY()

  alpha = GENERATE_ALPHA(destination, date, secret)
  A = 目的地的签名公钥
  // 使用群元素(曲线上的点)加法
  盲化公钥 = A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)

两种计算 A’ 的方法产生相同结果,符合要求。

签名

未盲化 leaseset 由未盲化 Ed25519 或 Red25519 签名私钥签名,
并使用未盲化 Ed25519 或 Red25519 签名公钥(签名类型 7 或 11)验证,如常。

如果签名公钥是离线的,
未盲化 leaseset 由未盲化临时 Ed25519 或 Red25519 签名私钥签名,
并使用未盲化 Ed25519 或 Red25519 临时签名公钥(签名类型 7 或 11)验证,如常。
有关加密 leaseset 的离线密钥的额外说明见下文。

对于加密 leaseset 的签名,我们使用 Red25519,基于 RedDSA
使用盲化密钥进行签名和验证。
Red25519 签名在 Ed25519 曲线上,使用 SHA-512 作为哈希。

Red25519 与标准 Ed25519 几乎相同,仅在以下方面不同。

签名/验证计算

加密 leaseset 的外层使用 Red25519 密钥和签名。

Red25519 与 Ed25519 几乎相同。有两个区别:

Red25519 私钥由随机数生成,然后必须对 L 取模,L 如上定义。
Ed25519 私钥由随机数生成,然后使用
字节 0 和 31 的位掩码进行“钳位”。Red25519 不这样做。
上述定义的 GENERATE_ALPHA() 和 BLIND_PRIVKEY() 函数使用 mod L 生成正确的
Red25519 私钥。

在 Red25519 中,签名计算 r 使用额外的随机数据,
并使用公钥值而非私钥的哈希。
由于随机数据,每次 Red25519 签名都不同,即使
使用相同密钥签名相同数据。

签名:

T = 80 随机字节
  r = H*(T || publickey || message)
  // 其余与 Ed25519 相同

验证:

// 与 Ed25519 相同

加密和处理

子凭据派生

作为盲化过程的一部分,我们需要确保加密 LS2 只能被知道对应目的地签名公钥的人解密。
不需要完整目的地。
为实现此目的,我们从签名公钥派生凭据:

A = 目的地的签名公钥
  stA = A 的签名类型,2 字节大端序 (0x0007 或 0x000b)
  stA' = A' 的签名类型,2 字节大端序 (0x000b)
  keydata = A || stA || stA'
  credential = H("credential", keydata)

个性化字符串确保凭据不会与用作 DHT 查找键的任何哈希冲突,例如纯目的地哈希。

对于给定盲化密钥,我们可以派生子凭据:

subcredential = H("subcredential", credential || blindedPublicKey)

子凭据包含在以下密钥派生过程中,将这些密钥绑定到知道目的地签名公钥的知识。

第 1 层加密

首先,准备密钥派生过程的输入:

outerInput = subcredential || publishedTimestamp

然后,生成随机盐:

outerSalt = CSRNG(32)

然后,派生用于加密第 1 层的密钥:

keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
  outerKey = keys[0:31]
  outerIV = keys[32:43]

最后,加密并序列化第 1 层明文:

outerCiphertext = outerSalt || ENCRYPT(outerKey, outerIV, outerPlaintext)

第 1 层解密

从第 1 层密文中解析盐:

outerSalt = outerCiphertext[0:31]

然后,派生用于加密第 1 层的密钥:

outerInput = subcredential || publishedTimestamp
  keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
  outerKey = keys[0:31]
  outerIV = keys[32:43]

最后,解密第 1 层密文:

outerPlaintext = DECRYPT(outerKey, outerIV, outerCiphertext[32:end])

第 2 层加密

当启用客户端授权时,authCookie 按下文所述计算。
当禁用客户端授权时,authCookie 为空字节数组。

加密过程与第 1 层类似:

innerInput = authCookie || subcredential || publishedTimestamp
  innerSalt = CSRNG(32)
  keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
  innerKey = keys[0:31]
  innerIV = keys[32:43]
  innerCiphertext = innerSalt || ENCRYPT(innerKey, innerIV, innerPlaintext)

第 2 层解密

当启用客户端授权时,authCookie 按下文所述计算。
当禁用客户端授权时,authCookie 为空字节数组。

解密过程与第 1 层类似:

innerInput = authCookie || subcredential || publishedTimestamp
  innerSalt = innerCiphertext[0:31]
  keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
  innerKey = keys[0:31]
  innerIV = keys[32:43]
  innerPlaintext = DECRYPT(innerKey, innerIV, innerCiphertext[32:end])

每个客户端授权

当目的地启用客户端授权时,服务器维护一个授权解密加密 LS2 数据的客户端列表。
每个客户端存储的数据取决于授权机制,包括每个客户端生成并通过安全带外机制发送给服务器的某种形式的密钥材料。

实现每个客户端授权有两种替代方案:

DH 客户端授权

每个客户端生成 DH 密钥对 [csk_i, cpk_i],并将公钥 cpk_i 发送给服务器。

服务器处理 ^^^^^^^^^^^^^^^^^ 服务器生成新的 authCookie 和临时 DH 密钥对:

authCookie = CSRNG(32)
  esk = GENERATE_PRIVATE()
  epk = DERIVE_PUBLIC(esk)

然后,对于每个授权客户端,服务器使用其公钥加密 authCookie

sharedSecret = DH(esk, cpk_i)
  authInput = sharedSecret || cpk_i || subcredential || publishedTimestamp
  okm = HKDF(epk, authInput, "ELS2_XCA", 52)
  clientKey_i = okm[0:31]
  clientIV_i = okm[32:43]
  clientID_i = okm[44:51]
  clientCookie_i = ENCRYPT(clientKey_i, clientIV_i, authCookie)

服务器将每个 [clientID_i, clientCookie_i] 元组放入加密 LS2 的第 1 层,连同 epk

客户端处理 ^^^^^^^^^^^^^^^^^ 客户端使用其私钥派生其预期的客户端标识符 clientID_i、加密密钥 clientKey_i 和加密 IV clientIV_i

sharedSecret = DH(csk_i, epk)
  authInput = sharedSecret || cpk_i || subcredential || publishedTimestamp
  okm = HKDF(epk, authInput, "ELS2_XCA", 52)
  clientKey_i = okm[0:31]
  clientIV_i = okm[32:43]
  clientID_i = okm[44:51]

然后,客户端在第 1 层授权数据中搜索包含 clientID_i 的条目。如果存在匹配条目,客户端解密以获取 authCookie

authCookie = DECRYPT(clientKey_i, clientIV_i, clientCookie_i)

预共享密钥客户端授权

每个客户端生成 32 字节密钥 psk_i,并将其发送给服务器。
或者,服务器可以生成密钥,并将其发送给一个或多个客户端。

服务器处理 ^^^^^^^^^^^^^^^^^ 服务器生成新的 authCookie 和盐:

authCookie = CSRNG(32)
  authSalt = CSRNG(32)

然后,对于每个授权客户端,服务器使用其预共享密钥加密 authCookie

authInput = psk_i || subcredential || publishedTimestamp
  okm = HKDF(authSalt, authInput, "ELS2PSKA", 52)
  clientKey_i = okm[0:31]
  clientIV_i = okm[32:43]
  clientID_i = okm[44:51]
  clientCookie_i = ENCRYPT(clientKey_i, clientIV_i, authCookie)

服务器将每个 [clientID_i, clientCookie_i] 元组放入加密 LS2 的第 1 层,连同 authSalt

客户端处理 ^^^^^^^^^^^^^^^^^ 客户端使用其预共享密钥派生其预期的客户端标识符 clientID_i、加密密钥 clientKey_i 和加密 IV clientIV_i

authInput = psk_i || subcredential || publishedTimestamp
  okm = HKDF(authSalt, authInput, "ELS2PSKA", 52)
  clientKey_i = okm[0:31]
  clientIV_i = okm[32:43]
  clientID_i = okm[44:51]

然后,客户端在第 1 层授权数据中搜索包含 clientID_i 的条目。如果存在匹配条目,客户端解密以获取 authCookie

authCookie = DECRYPT(clientKey_i, clientIV_i, clientCookie_i)

安全考虑

上述两种客户端授权机制都提供客户端成员的隐私。
只知道目的地的实体可以看到当前有多少客户端订阅,但无法跟踪哪些客户端被添加或撤销。

服务器每次生成加密 LS2 时应随机化客户端顺序,以防止客户端了解其在列表中的位置并推断其他客户端何时被添加或撤销。

服务器可以选择通过在授权数据列表中插入随机条目来隐藏订阅的客户端数量。

DH 客户端授权的优点 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  • 方案的安全性不完全依赖于客户端密钥材料的带外交换。客户端的私钥永远不需要离开其设备,因此能够拦截带外交换但无法破解 DH 算法的对手无法解密加密 LS2,或确定客户端被授予访问权限的时间。

DH 客户端授权的缺点 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  • 服务器端需要 N + 1 次 DH 操作(N 个客户端)。
  • 客户端需要一次 DH 操作。
  • 客户端需要生成密钥。

PSK 客户端授权的优点 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  • 不需要 DH 操作。
  • 允许服务器生成密钥。
  • 允许服务器与多个客户端共享相同密钥(如果需要)。

PSK 客户端授权的缺点 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  • 方案的安全性严重依赖于客户端密钥材料的带外交换。能够拦截特定客户端交换的对手可以解密该客户端被授权的任何后续加密 LS2,并确定客户端访问何时被撤销。

带 Base 32 地址的加密 LS

参见提案 149。

你不能对 bittorrent 使用加密 LS2,因为紧凑公告回复是 32 字节。
32 字节仅包含哈希。没有空间指示 leaseset 是否加密,或签名类型。

带离线密钥的加密 LS

对于带离线密钥的加密 leaseset,盲化私钥也必须离线生成,每天一个。

由于可选的离线签名块在加密 leaseset 的明文部分,
任何抓取 floodfill 的人都可以使用它来跟踪 leaseset(但无法解密)数天。
为防止此情况,密钥所有者也应为每天生成新的临时密钥。
临时和盲化密钥都可以提前生成,并批量交付给路由器。

本提案未定义用于打包多个临时和盲化密钥并提供给客户端或路由器的文件格式。
本提案未定义支持带离线密钥的加密 leaseset 的 I2CP 协议增强。

说明

  • 使用加密 leaseset 的服务会将加密版本发布到 floodfill。
    但为提高效率,一旦通过认证(例如通过白名单),
    它会向客户端发送未加密的 leaseset 到封装的大蒜消息中。

  • Floodfill 可能会将最大大小限制为合理值以防止滥用。

  • 解密后,应进行几项检查,包括内部时间戳和过期时间与顶层匹配。

  • 选择了 ChaCha20 而非 AES。虽然在有 AES 硬件支持时速度相似,
    但在没有 AES 硬件支持时(如低端 ARM 设备),ChaCha20 快 2.5-3 倍。

  • 我们对速度不够关心,因此不使用带密钥的 BLAKE2b。
    它的输出大小足以容纳我们所需的最大 n(或我们可以用计数器参数调用一次以获取每个所需密钥)。
    BLAKE2b 比 SHA-256 快得多,带密钥的 BLAKE2b 会减少哈希函数调用总数。
    但参见提案 148,其中提议我们因其他原因切换到 BLAKE2b。
    参见 Secure key derivation performance

Meta LS2

这用于替换多宿主。像任何 leaseset 一样,由创建者签名。
这是目的地哈希的认证列表。

Meta LS2 是树结构的顶部,也可能是中间节点。
它包含多个条目,每个指向一个 LS、LS2 或另一个 Meta LS2,
以支持大规模多宿主。
Meta LS2 可以包含 LS、LS2 和 Meta LS2 条目的混合。
树的叶子始终是 LS 或 LS2。
树是有向无环图(DAG);禁止循环;进行查找的客户端必须检测并拒绝跟随循环。

Meta LS2 的过期时间可以比标准 LS 或 LS2 长得多。
顶级可能在发布日期后几小时过期。
最大过期时间将由 floodfill 和客户端强制执行,待定。

Meta LS2 的用例是大规模多宿主,但在路由器重启时对路由器与 leaseset 的关联保护不比现在使用 LS 或 LS2 提供的更多。
这相当于“facebook”用例,可能不需要关联保护。此用例可能需要离线密钥,
在树的每个节点的标准头中提供。

叶路由器、中间和主 Meta LS 签名者之间协调的后端协议未在此指定。
要求非常简单——只需验证对等方是否在线,
并每几小时发布一个新 LS。唯一复杂的是在失败时为顶级或中间级 Meta LS 选择新发布者。

在提案 140 “隐式多宿主”中记录了混合 leaseset,其中来自多个路由器的租约被组合、签名并在单个 leaseset 中发布。
此提案如所写不可行,因为流连接不会“粘滞”到单个路由器,参见 http://zzz.i 2p/topics/2335 。

隐式多宿主的后端协议和与路由器及客户端内部的交互将非常复杂。

为避免顶级 Meta LS 的 floodfill 过载,过期时间至少应为几小时。
客户端必须缓存顶级 Meta LS,并在未过期时跨重启持久化。

我们需要定义客户端遍历树的算法,包括回退,
以便使用分散。一些哈希距离、成本和随机性的函数。
如果节点同时有 LS 或 LS2 和 Meta LS,我们需要知道何时可以使用这些 leaseset,何时应继续遍历树。

查找使用
标准 LS 标志 (1)
存储使用
Meta LS2 类型 (7)
存储于
目的地的哈希
此哈希随后用于生成每日“路由密钥”,如 LS1
典型过期时间
数小时。最大 18.2 小时(65535 秒)

“主”目的地或协调者,或中间协调者发布

格式

如上所述的标准 LS2 头

  Meta LS2 类型特定部分
  - 属性 (如通用结构规范中指定的映射,若无则为 2 零字节)
  - 条目数量 (1 字节) 最大值待定
  - 条目。每个条目包含:(40 字节)
    - 哈希 (32 字节)
    - 标志 (2 字节)
      待定。为兼容未来用途设为零。
    - 类型 (1 字节) 其引用的 LS 类型;
      1 表示 LS,3 表示 LS2,5 表示加密,7 表示 meta,0 表示未知。
    - 成本(优先级)(1 字节)
    - 过期 (4 字节) (4 字节,大端序,自纪元以来的秒数,2106 年回绕)
  - 撤销数量 (1 字节) 最大值待定
  - 撤销:每个撤销包含:(32 字节)
    - 哈希 (32 字节)

  标准 LS2 签名:
  - 签名 (40+ 字节)
    对上述所有内容的签名。

标志和属性:供将来使用

说明

  • 使用此功能的分布式服务将有一个或多个拥有服务目的地私钥的“主”节点。
    他们将(带外)确定当前活动目的地列表并发布 Meta LS2。
    为冗余,多个主节点可以多宿主(即并发发布)Meta LS2。

  • 分布式服务可以从单个目的地或使用旧式多宿主开始,然后过渡到 Meta LS2。
    标准 LS 查找可以返回 LS、LS2 或 Meta LS2 中的任何一个。

  • 当服务使用 Meta LS2 时,它没有隧道(租约)。

服务记录

这是单个记录,说明目的地正在参与某项服务。
它由参与者发送到 floodfill。
它永远不会由 floodfill 单独发送,仅作为服务列表的一部分。
服务记录也用于撤销参与服务,通过将过期时间设为零。

这不是 LS2,但使用标准 LS2 头和签名格式。

查找使用
n/a,参见服务列表
存储使用
服务记录类型 (9)
存储于
服务名称的哈希
此哈希随后用于生成每日“路由密钥”,如 LS1
典型过期时间
数小时。最大 18.2 小时(65535 秒)

目的地发布

格式

如上所述的标准 LS2 头

  服务记录类型特定部分
  - 端口 (2 字节,大端序) (未指定则为 0)
  - 服务名称的哈希 (32 字节)

  标准 LS2 签名:
  - 签名 (40+ 字节)
    对上述所有内容的签名。

说明

  • 如果过期时间全为零,floodfill 应撤销记录,不再将其包含在服务列表中。

  • 存储:floodfill 可严格限制这些记录的存储,限制每个哈希存储的记录数量及其过期时间。
    也可使用白名单。

  • 任何其他在相同哈希的 netdb 类型优先,因此服务记录永远不能覆盖 LS/RI,但 LS/RI 会覆盖该哈希的所有服务记录。

服务列表

这与 LS2 完全不同,使用不同格式。

服务列表由 floodfill 创建和签名。它是无认证的,
因为任何人都可以通过向 floodfill 发布服务记录来加入服务。

服务列表包含短服务记录,而非完整服务记录。
它们包含签名但只有哈希,没有完整目的地,因此无法在没有完整目的地的情况下验证。

服务列表的安全性(如果有)和可取性待定。
floodfill 可限制发布和查找到服务白名单,
但该白名单可能因实现或操作员偏好而异。
可能无法在实现间就共同基础白名单达成共识。

如果服务名称包含在上述服务记录中,
floodfill 操作员可能反对;如果仅包含哈希,
则无验证,服务记录可能“提前”进入任何其他 netdb 类型并存储在 floodfill 中。

查找使用
服务列表查找类型 (11)
存储使用
服务列表类型 (11)
存储于
服务名称的哈希
此哈希随后用于生成每日“路由密钥”,如 LS1
典型过期时间
数小时,未在列表本身指定,取决于本地策略

无人,从不发送到 floodfill,从不泛洪。

格式

不使用上述指定的标准 LS2 头。

- 类型 (1 字节)
    实际上不在头中,但属于签名覆盖的数据。
    从数据库存储消息的字段中获取。
  - 服务名称的哈希(隐式,在数据库存储消息中)
  - 创建者(floodfill)的哈希 (32 字节)
  - 发布时间戳 (8 字节,大端序)

  - 短服务记录数量 (1 字节)
  - 短服务记录列表:
    每个短服务记录包含 (90+ 字节)
    - 目的地哈希 (32 字节)
    - 发布时间戳 (8 字节,大端序)
    - 过期 (4 字节,大端序) (自发布起的毫秒偏移)
    - 标志 (2 字节)
    - 端口 (2 字节,大端序)
    - 签名长度 (2 字节,大端序)
    - 目的地签名 (40+ 字节)

  - 撤销记录数量 (1 字节)
  - 撤销记录列表:
    每个撤销记录包含 (86+ 字节)
    - 目的地哈希 (32 字节)
    - 发布时间戳 (8 字节,大端序)
    - 标志 (2 字节)
    - 端口 (2 字节,大端序)
    - 签名长度 (2 字节,大端序)
    - 目的地签名 (40+ 字节)

  - floodfill 签名 (40+ 字节)
    对上述所有内容的签名。

验证服务列表签名:

  • 前缀服务名称的哈希
  • 移除创建者的哈希
  • 验证修改后内容的签名

验证每个短服务记录签名:

  • 获取目的地
  • 验证 (发布时间戳 + 过期 + 标志 + 端口 + 服务名称的哈希) 的签名

验证每个撤销记录签名:

  • 获取目的地
  • 验证 (发布时间戳 + 4 个零字节 + 标志 + 端口 + 服务名称的哈希) 的签名

说明

  • 我们使用签名长度而非签名类型,以支持未知签名类型。

  • 服务列表没有过期时间,接收者可根据策略或单个记录的过期时间自行决定。

  • 服务列表不泛洪,只有单个服务记录泛洪。每个 floodfill 创建、签名并缓存服务列表。
    floodfill 使用其自身策略决定缓存时间和最大服务及撤销记录数。

通用结构规范变更要求

密钥证书

本提案范围外。
添加到 ECIES 提案 144 和 145。

新中间结构

添加 Lease2、MetaLease、LeaseSet2Header 和 OfflineSignature 的新结构。
自 0.9.38 版本起生效。

新 NetDB 类型

添加每个新 leaseset 类型的结构,从上文整合。
对于 LeaseSet2、EncryptedLeaseSet 和 MetaLeaseSet,
自 0.9.38 版本起生效。
对于服务记录和服务列表,
初步且未排期。

新签名类型

添加 RedDSA_SHA512_Ed25519 类型 11。
公钥 32 字节;私钥 32 字节;哈希 64 字节;签名 64 字节。

加密规范变更要求

本提案范围外。
参见提案 144 和 145。

I2NP 变更要求

添加说明:LS2 只能发布到具有最低版本的 floodfill。

数据库查找消息

添加服务列表查找类型。

变更

标志字节:查找类型字段,当前为位 3-2,扩展到 4-2。
  查找类型 0x04 定义为服务列表查找。

  添加说明:服务列表查找只能发送到具有最低版本的 floodfill。
  最低版本为 0.9.38。

数据库存储消息

添加所有新存储类型。

变更

类型字节:类型字段,当前为位 0,扩展到 3-0。
  类型 3 定义为 LS2 存储。
  类型 5 定义为加密 LS2 存储。
  类型 7 定义为 meta LS2 存储。
  类型 9 定义为服务记录存储。
  类型 11 定义为服务列表存储。
  其他类型未定义且无效。

  添加说明:所有新类型只能发布到具有最低版本的 floodfill。
  最低版本为 0.9.38。

I2CP 变更要求

I2CP 选项

路由器端解释的新选项,在 SessionConfig 映射中发送:


  i2cp.leaseSetType=nnn       在创建 leaseset 消息中发送的 leaseset 类型
                              值与上表中的 netdb 存储类型相同。
                              客户端端解释,但也传递给路由器的 SessionConfig,以声明意图和检查支持。

  i2cp.leaseSetEncType=nnn[,nnn]  要使用的加密类型。
                                  客户端端解释,但也传递给路由器的
                                  SessionConfig,以声明意图和检查支持。
                                  参见提案 144 和 145。

  i2cp.leaseSetOfflineExpiration=nnn  离线签名的过期时间,ASCII,
                                      自纪元以来的秒数。

  i2cp.leaseSetTransientPublicKey=[type:]b64  临时私钥的 base64,
                                              前缀为可选的签名类型编号
                                              或名称,默认 DSA_SHA1。
                                              长度由签名类型推断

  i2cp.leaseSetOfflineSignature=b64   离线签名的 base64。
                                      长度由目的地
                                      签名公钥类型推断

  i2cp.leaseSetSecret=b64     用于盲化 leaseset
                              地址的密钥的 base64,默认 ""

  i2cp.leaseSetAuthType=nnn   加密 LS2 的认证类型。
                              0 表示无每个客户端认证(默认)
                              1 表示 DH 每个客户端认证
                              2 表示 PSK 每个客户端认证

  i2cp.leaseSetPrivKey=b64    路由器用于解密加密 LS2 的
                              base64 私钥,
                              仅当启用每个客户端认证时

客户端端解释的新选项:


  i2cp.leaseSetType=nnn     在创建 leaseset 消息中发送的 leaseset 类型
                            值与上表中的 netdb 存储类型相同。
                            客户端端解释,但也传递给路由器的
                            SessionConfig,以声明意图和检查支持。

  i2cp.leaseSetEncType=nnn[,nnn]  要使用的加密类型。
                                  客户端端解释,但也传递给路由器的
                                  SessionConfig,以声明意图和检查支持。
                                  参见提案 144 和 145。

  i2cp.leaseSetSecret=b64     用于盲化 leaseset
                              地址的密钥的 base64,默认 ""

  i2cp.leaseSetAuthType=nnn       加密 LS2 的认证类型。
                                  0 表示无每个客户端认证(默认)
                                  1 表示 DH 每个客户端认证
                                  2 表示 PSK 每个客户端认证

  i2cp.leaseSetBlindedType=nnn   加密 LS2 的盲化密钥的签名类型。
                                 默认取决于目的地签名类型。

  i2cp.leaseSetClient.dh.nnn=b64name:b64pubkey   客户端名称的 base64(忽略,仅用于 UI),
                                                 后跟 ':',再跟用于 DH 每个客户端认证的公钥的 base64。nnn 从 0 开始

  i2cp.leaseSetClient.psk.nnn=b64name:b64privkey   客户端名称的 base64(忽略,仅用于 UI),
                                                   后跟 ':',再跟用于 PSK 每个客户端认证的私钥的 base64。nnn 从 0 开始

会话配置

注意,对于离线签名,选项
i2cp.leaseSetOfflineExpiration、
i2cp.leaseSetTransientPublicKey 和
i2cp.leaseSetOfflineSignature 是必需的,
且签名由临时签名私钥完成。

请求 leaseset 消息

路由器到客户端。
无变更。
租约以 8 字节时间戳发送,即使返回的 leaseset 将是带 4 字节时间戳的 LS2。
注意,响应可能是创建 leaseset 或创建 leaseset2 消息。

请求可变 leaseset 消息

路由器到客户端。
无变更。
租约以 8 字节时间戳发送,即使返回的 leaseset 将是带 4 字节时间戳的 LS2。
注意,响应可能是创建 leaseset 或创建 leaseset2 消息。

创建 leaseset2 消息

客户端到路由器。
新消息,用于替代创建 leaseset 消息。

理由

  • 为让路由器解析存储类型,类型必须在消息中,
    除非在会话配置中提前传递给路由器。
    为共用解析代码,更容易在消息本身中包含它。

  • 为让路由器知道私钥的类型和长度,
    它必须在 leaseset 之后,除非解析器在会话配置中提前知道类型。
    为共用解析代码,更容易从消息本身知道它。

  • 签名私钥,以前为撤销定义但未使用,
    在 LS2 中不存在。

消息类型

创建 leaseset2 消息的消息类型为 41。

格式

会话 ID
  类型字节:后续 leaseset 的类型
             类型 1 是 LS
             类型 3 是 LS2
             类型 5 是加密 LS2
             类型 7 是 meta LS2
  LeaseSet:上述指定的类型
  后续私钥数量 (1 字节)
  加密私钥:对于 leaseset 中的每个公钥,
                           按相同顺序
                           (Meta LS2 不存在)
                           - 加密类型 (2 字节,大端序)
                           - 加密密钥长度 (2 字节,大端序)
                           - 加密密钥 (指定字节数)

说明

  • 最低路由器版本为 0.9.39。
  • 0.9.38 中有消息类型 40 的初步版本,但格式已更改。
    类型 40 已废弃且不受支持。

问题

  • 需要更多变更以支持加密和 meta LS。

盲化信息消息

客户端到路由器。
新消息。

理由

  • 路由器需要知道目的地是否被盲化。
    如果被盲化并使用密钥或每个客户端认证,
    它也需要有该信息。

  • 新格式 b32 地址(“b33”)的主机查找
    告诉路由器地址被盲化,但没有机制在主机查找消息中
    传递密钥或私钥给路由器。
    虽然我们可以扩展主机查找消息以添加该信息,
    但定义新消息更清晰。

  • 我们需要客户端告诉路由器的程序化方式。
    否则,用户必须手动配置每个目的地。

用法

在客户端向盲化目的地发送消息之前,必须
在主机查找消息中查找“b33”,或发送盲化信息消息。
如果盲化目的地需要密钥或每个客户端认证,
客户端必须发送盲化信息消息。

路由器不对此消息回复。

消息类型

盲化信息消息的消息类型为 42。

格式

会话 ID
  标志:       1 字节
               位顺序:76543210
               位 0:0 表示所有人,1 表示每个客户端
               位 3-1:认证方案,如果位 0 设为 1(每个客户端),否则为 000
                         000:DH 客户端认证(或无每个客户端认证)
                         001:PSK 客户端认证
               位 4:1 表示需要密钥,0 表示不需要密钥
               位 7-5:未使用,为未来兼容性设为 0
  类型字节:   后续端点类型
               类型 0 是哈希
               类型 1 是主机名字符串
               类型 2 是目的地
               类型 3 是签名类型和签名公钥
  盲化类型:  2 字节盲化签名类型(大端序)
  过期:  4 字节,大端序,自纪元以来的秒数
  端点:    上述指定的数据
               类型 0:32 字节二进制哈希
               类型 1:主机名字符串
               类型 2:二进制目的地
               类型 3:2 字节签名类型(大端序)
                           签名公钥(长度由签名类型隐含)
  私钥:      仅当标志位 0 设为 1 时
               32 字节 ECIES_X25519 私钥
  密钥:      仅当标志位 4 设为 1 时
               密钥字符串

说明

  • 最低路由器版本为 0.9.43

问题

主机回复消息(加密)

为支持“b33”主机名的查找并返回指示
如果路由器没有所需信息,我们为
主机回复消息定义额外的结果代码,如下:

2: 需要查找密码
   3: 需要私钥
   4: 需要查找密码和私钥
   5: leaseset 解密失败

值 1-255 已定义为错误,因此没有
向后兼容性问题。

Meta 重定向消息

路由器到客户端。
新消息。

理由

客户端事先不知道给定哈希将解析
为 Meta LS。

如果对目的地的 leaseset 查找返回 Meta LS,
路由器将进行递归解析。
对于数据报,客户端端不需要知道;
但对于流,协议在 SYN ACK 中检查目的地,
它必须知道“真实”目的地。
因此,我们需要新消息。

用法

路由器维护从 meta LS 使用的实际目的地的缓存。
当客户端向解析为 meta LS 的目的地发送消息时,
路由器检查缓存中上次使用的实际目的地。
如果缓存为空,路由器从 meta LS 选择一个目的地,
并查找 leaseset。
如果 leaseset 查找成功,路由器将该目的地
添加到缓存,并向客户端发送 Meta 重定向消息。
这只做一次,除非目的地过期并必须更改。
客户端也必须在需要时缓存信息。
Meta 重定向消息不会作为每个 SendMessage 的回复发送。

路由器只向版本 0.9.47 或更高的客户端发送此消息。

客户端不对此消息回复。

消息类型

Meta 重定向消息的消息类型为 43。

格式

会话 ID (2 字节) 来自发送消息的值。
  路由器生成的消息 ID