BitChat 协议白皮书

BitChat 是一种去中心化的点对点消息传递应用,旨在通过临时、专用网络实现安全、私密和抗审查的通信。它采用分层架构,结合了现代加密技术和灵活的应用协议,利用 Noise 协议框架建立相互认证的端到端加密会话,实现了身份管理、会话生命周期、消息帧和安全。

BitChat 协议白皮书

版本 1.1

日期:2025 年 7 月 25 日


摘要

BitChat 是一款去中心化、点对点消息应用,旨在通过临时的、自组织网络进行安全、私密且抗审查的通信。 本白皮书详细介绍了 BitChat 协议栈,这是一种分层架构,将现代密码学基础与灵活的应用程序协议相结合。 BitChat 的核心是利用 Noise 协议框架(特别是 XX 模式)在对等方之间建立相互认证的端到端加密会话。 本文档提供了身份管理、会话生命周期、消息成帧和安全注意事项的技术规范,这些规范是 BitChat 网络的基础。


1. 简介

在中心化通信平台时代,BitChat 通过在没有中心服务器的情况下运行,提供了一种具有弹性的替代方案。 它专为互联网连接不可用或不可信的场景而设计,例如抗议活动、自然灾害或偏远地区。 通信直接在设备之间通过蓝牙低功耗 (BLE) 等传输方式进行。

BitChat 协议的设计目标是:

  • 保密性: 所有通信对于第三方必须是不可读的。
  • 身份验证: 用户必须能够验证其通信对象的身份。
  • 完整性: 消息在传输过程中不得被篡改。
  • 前向保密: 长期身份密钥的泄露不得危及过去的会话密钥。
  • 不可否认性: 应该很难通过密码学证明特定用户发送了特定消息。
  • 弹性: 该协议必须在有损、低带宽环境中可靠地运行。

本文档详细说明了为实现这些目标而设计的协议的技术细节。


2. 协议栈

BitChat 协议是一个四层栈。 这种分层方法分离了关注点,从而实现了模块化和未来的可扩展性。

graph TD
    A[应用层] --> B[会话层];
    B --> C[加密层];
    C --> D[传输层];

    subgraph "BitChat 应用"
        A
    end

    subgraph "消息成帧 & 状态"
        B
    end

    subgraph "Noise 协议框架"
        C
    end

    subgraph "BLE, Wi-Fi Direct, etc."
        D
    end

    style A fill:#cde4ff
    style B fill:#b5d8ff
    style C fill:#9ac2ff
    style D fill:#7eadff
  • 应用层: 定义了面向用户的消息 (BitchatMessage)、确认 (DeliveryAck) 和其他应用层数据的结构。
  • 会话层: 管理总体通信数据包 (BitchatPacket)。 这包括路由信息 (TTL)、消息类型、分片和序列化为紧凑的二进制格式。
  • 加密层: 使用 Noise 协议框架建立和管理安全通道。 它负责密码学握手、会话管理和传输消息的加密/解密。
  • 传输层: 用于数据传输的底层物理介质,例如蓝牙低功耗 (BLE)。 这一层从核心协议中抽象出来。

3. 身份和密钥管理

对等方在 BitChat 中的身份由两个持久的密码密钥对定义,这些密钥对在首次启动时生成并安全地存储在设备的 Keychain 中。

  1. Noise 静态密钥对 (Curve25519): 这是用于 Noise 协议握手的长期身份密钥。 该密钥的公共部分与对等方共享,以建立安全会话。
  2. 签名密钥对 (Ed25519): 此密钥用于签署公告和其他需要不可否认性的协议消息,例如将公钥绑定到昵称。

3.1. 指纹

用户唯一、可验证的指纹是其 Noise 静态公钥SHA-256 哈希。 这提供了一种用户友好且安全的方式来带外验证身份(例如,通过大声朗读或扫描二维码)。

Fingerprint = SHA256(StaticPublicKey_Curve25519)

3.2. 身份管理

SecureIdentityStateManager 类负责管理所有密码学身份材料和社交元数据(昵称、信任级别等)。 它使用内存缓存来提高性能,并将此缓存持久化到 Keychain,在之后使用单独的 AES-GCM 密钥对其进行加密。


4. 社交信任层

除了密码学身份之外,BitChat 还包含一个社交信任层,允许用户管理他们与对等方的关系。 此功能由 SecureIdentityStateManager 处理。

4.1. 对等方验证

虽然 Noise 握手通过密码学验证了对等方的密钥,但它并未确认持有该设备的真人的真实身份。 为了解决这个问题,用户可以通过比较指纹来执行带外 (OOB) 验证。 一旦用户确认对等方的指纹与他们期望的指纹匹配,他们就可以将该对等方标记为“已验证”。 此状态本地存储并显示在 UI 中,为以后的对话提供了强大的身份保证。

4.2. 收藏夹和阻止

为了改善用户体验并提供对交互的控制,该协议支持:

  • 收藏夹: 用户可以将受信任或经常联系的对等方标记为“收藏夹”。 这是一种本地指定,应用程序可以使用它来优先处理通知或更突出地显示对等方。
  • 阻止: 用户可以阻止对等方。 阻止对等方后,应用程序将在最早的阶段丢弃来自该对等方指纹的任何传入数据包,从而有效地使他们静音,而不会通知被阻止的对等方。

5. Noise 协议层

BitChat 实现了 Noise 协议框架,以提供强大的、经过身份验证的端到端加密。

5.1. 协议名称

实现的特定 Noise 协议是:

Noise_XX_25519_ChaChaPoly_SHA256

  • XX 模式: 此握手模式提供相互身份验证和前向保密。 它不需要任何一方在握手开始之前知道对方的静态公钥。 密钥在三部分握手期间交换和验证。 这对于去中心化的 P2P 环境来说是理想的。
  • 25519 使用的 Diffie-Hellman 函数是 Curve25519。
  • ChaChaPoly AEAD(带有关联数据的经过身份验证的加密)密码是 ChaCha20-Poly1305。
  • SHA256 用于所有密码学哈希运算的哈希函数是 SHA-256。

5.2. XX 握手

XX 握手包含启动者和响应者之间交换的三个消息,以建立共享密钥并派生传输加密密钥。

sequenceDiagram
    participant I as 启动者
    participant R as 响应者

    Note over I, R: 预计算: h = SHA256(protocol_name)

    I->>R: -> e
    Note right of I: I 生成临时密钥 `e_i`.<br/>h = SHA256(h + e_i.pub)

    R->>I: <- e, ee, s, es
    Note left of R: R 生成临时密钥 `e_r`.<br/>h = SHA256(h + e_r.pub)<br/>MixKey(DH(e_i, e_r))<br/>R 发送静态密钥 `s_r`, 已加密.<br/>h = SHA256(h + ciphertext)<br/>MixKey(DH(e_i, s_r))

    I->>R: -> s, se
    Note right of I: I 解密并验证 `s_r`.<br/>I 发送静态密钥 `s_i`, 已加密.<br/>h = SHA256(h + ciphertext)<br/>MixKey(DH(s_i, e_r))

    Note over I, R: 握手完成. 传输密钥已派生.

握手流程:

  1. 启动者 -> 响应者: 启动者生成一个新的临时密钥对 (e_i) 并将公共部分发送给响应者。
  2. 响应者 -> 启动者: 响应者接收启动者的临时公钥。 然后,它生成自己的临时密钥对 (e_r),与启动者的临时密钥 (ee) 执行 DH 交换,发送自己的静态公钥 (s_r) 并使用生成的对称密钥对其进行加密,并在启动者的临时密钥和自己的静态密钥 (es) 之间执行另一次 DH 交换。
  3. 启动者 -> 响应者: 启动者接收响应者的消息,解密响应者的静态密钥并对其进行身份验证。 然后,启动者发送自己的静态密钥 (s_i) 并对其进行加密,并在其静态密钥和响应者的临时密钥 (se) 之间执行最终 DH 交换。

完成后,双方共享一组对称密钥,用于双向传输消息加密。 最终的握手哈希用于通道绑定。

5.3. 会话管理

NoiseSessionManager 类管理所有活动的 Noise 会话。 它处理:

  • 为新对等方创建会话。
  • 协调握手过程以防止竞争情况。
  • 存储生成的传输密码 (sendCipherreceiveCipher)。
  • 定期检查是否需要重新配置会话密钥以增强安全性。

6. BitChat 会话和应用程序协议

一旦 Noise 会话建立,对等方将交换 BitchatPacket 结构,这些结构被加密为 Noise 传输消息的有效负载。

6.1. 二进制数据包格式 (BitchatPacket)

为了最大限度地减少带宽,BitchatPacket 被序列化为紧凑的二进制格式。 该结构设计为尽可能固定大小,以抵抗流量分析。

字段 大小(字节) 描述
标头 13 固定大小的标头
版本 1 协议版本(当前为 1)。
类型 1 消息类型(例如,messagedeliveryAcknoiseHandshakeInit)。 请参阅 MessageType 枚举。
TTL 1 用于网状网络路由的生存时间。 在每个跃点处递减。
时间戳 8 数据包创建的 UInt64 毫秒时间戳。
标志 1 可选字段的位掩码(hasRecipienthasSignatureisCompressed)。
有效负载长度 2 有效负载字段的 UInt16 长度。
变量 ... 可变大小的字段
发送方 ID 8 发送方的 8 字节截断对等方 ID。
接收方 ID 8 (可选) 接收方的 8 字节截断对等方 ID。 如果设置了 hasRecipient 标志,则显示。 如果为 0xFF..FF,则广播。
有效负载 变量 数据包的实际内容,如 Type 字段所定义。
签名 64(可选) 数据包的 Ed25519 签名。 如果设置了 hasSignature 标志,则显示。

填充: 所有数据包都使用 PKCS#7 样式方案填充到下一个标准块大小(256、512、1024 或 2048 字节),以模糊网络观察员的真实消息长度。

6.2. 应用程序消息格式 (BitchatMessage)

对于类型为 message 的数据包,有效负载是包含聊天内容的二进制序列化 BitchatMessage

字段 大小(字节) 描述
标志 1 可选字段的位掩码(isRelayisPrivatehasOriginalSender)。
时间戳 8 消息创建的 UInt64 毫秒时间戳。
ID 1 + len 消息的 UUID 字符串。
发送方 1 + len 发送方的昵称。
内容 2 + len UTF-8 编码的消息内容。
原始发送方 1 + len (opt) 如果消息是中继,则为原始发送方的昵称。
接收方昵称 1 + len (opt) 私有消息的接收方昵称。

7. 消息路由和传播

BitChat 作为去中心化的网状网络运行,这意味着没有中央服务器来路由消息。 数据包通过网络从对等方传播到对等方。 该协议支持多种消息传递模式。

7.1. 直接连接

这是最简单的情况。 如果对等方 A 和对等方 B 直接连接,他们可以在建立相互验证的 Noise 会话后交换数据包。 所有数据包都使用从握手派生的传输密码进行加密。

7.2. 使用 Bloom 过滤器的有效 Gossip

为了将消息发送到未直接连接的对等方,BitChat 采用“泛洪”或“gossip”协议。 当对等方收到未发往它的数据包时,它将充当一个中继。为了防止无限路由循环并最大程度地减少内存使用量,该协议使用 OptimizedBloomFilter 来跟踪最近看到的 数据包 ID。

逻辑如下:

  1. 一个对等方接收到一个数据包。
  2. 它会检查 Bloom 过滤器,以查看数据包的 ID 是否可能以前见过。 如果是这样,则丢弃该数据包。 Bloom 过滤器可能有误报(尽管很少见),但它们保证没有误报。 这意味着,虽然由于误报可能导致错误地丢弃某些数据包,但 gossip 协议的冗余性可确保这些数据包最终将通过与其他对等方的后续交换来接收。
  3. 如果数据包是新的,则将其 ID 添加到 Bloom 过滤器。
  4. 对等方会减少数据包的生存时间 (TTL) 字段。
  5. 如果 TTL 大于零,则对等方会将数据包重新广播到所有连接的对等方,除了接收该数据包的对等方。

这种机制允许数据包有效地“泛洪”通过网络,从而最大限度地提高了到达其目的地的机会,同时使用最少的资源来防止循环。

7.3. 生存时间 (TTL)

每个 BitchatPacket 都包含一个 8 位 TTL 字段。 该值由始发对等方设置,并在每个中继跃点处减一。 如果对等方收到一个数据包并将其 TTL 减少到 0,它将处理该数据包(如果它是接收方),但不会进一步中继它。 这是防止数据包在网状网络中无休止地循环的关键机制。

7.4. 私有消息与广播消息

路由逻辑尊重私有消息的机密性:

  • 私有消息: 具有特定 recipientID 的数据包是私有消息。 中继节点转发整个加密的 Noise 消息,而无法访问内部 BitchatPacket 或其有效负载。 只有与发送方共享正确 Noise 会话密钥的最终接收方才能解密该数据包。
  • 广播消息: 具有特殊广播 recipientID (0xFFFFFFFFFFFFFFFF) 的数据包旨在发送给所有对等方。 任何接收并解密广播消息的对等方都将处理其内容。 它仍将根据泛洪算法进行中继,以确保其到达整个网络。

7.5. 消息可靠性和生命周期

为了在不可靠的有损网络中运行,该协议包括用于跟踪消息生命周期并确保其传递的功能。

  • 传递确认 (DeliveryAck): 当私有消息到达其最终目的地时,接收方的设备会将 DeliveryAck 数据包发回给原始发送方。 此确认包含原始消息的 ID。
  • 已读回执 (ReadReceipt): 在消息显示在接收方的屏幕上之后,应用程序可以发送 ReadReceipt,其中还包含原始消息 ID,以通知发送方该消息已被查看。
  • 消息重试服务: 发送方维护一个 MessageRetryService,该服务跟踪传出消息。 如果在特定时间窗口内未收到消息的 DeliveryAck,该服务将自动重新发送该消息,从而创建更具弹性的用户体验。

7.6. 分片

传输层(如 BLE)具有最大传输单元 (MTU),该单元限制单个数据包的大小。 为了处理大于此限制的消息,BitChat 实现了分片协议。

  • fragmentStart 类型为此的数据包标记分片消息的开头。 它包含有关总大小和分片数量的元数据。
  • fragmentContinue 这些数据包携带消息数据的中间块。
  • fragmentEnd 此数据包携带消息的最终块,并指示接收方开始重新组装。

接收对等方收集所有分片,然后按正确的顺序重新组装,然后将完整消息传递到应用程序层。


8. 安全注意事项

  • 重放攻击: Noise 传输消息包含一个 nonce,该 nonce 会为每个消息递增。 NoiseCipherState 实现了一个滑动窗口重放保护机制,以检测和丢弃重放的或乱序的消息。
  • 拒绝服务: 实现了 NoiseRateLimiter,以防止来自单个对等方的快速、重复的握手尝试导致资源耗尽。
  • 密钥泄露冒充: XX 模式验证双方的身份,从而防止攻击者将一方冒充为另一方。
  • 身份绑定: 虽然 Noise 握手验证了密码密钥,但将这些密钥绑定到人类可读的昵称是在应用程序层处理的。 用户必须带外验证指纹才能防止中间人攻击。
  • 流量分析: 对所有数据包使用固定大小的填充有助于模糊通信的确切性质和内容,从而使网络级别的攻击者更难以根据消息大小推断信息。

9. 结论

BitChat 协议为去中心化的点对点通信提供了强大而安全的基础。 通过在备受推崇的 Noise 协议框架之上分层一个灵活的应用程序协议,它可以实现强大的保密性、身份验证和前向保密。 紧凑的二进制格式和周到的安全注意事项(例如速率限制和流量分析抵抗)使其适合在具有挑战性的网络环境中使用。

  • 原文链接: github.com/permissionles...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

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