【免费下载链接】lolPing
League of Legends ping wheel for your Windows desktop. Hold Alt, drag, and ping anywhere, with the original animations and sounds.
lolPing 是一款让《英雄联盟》信号(ping)出现在整个桌面的工具,按住 Alt 拖动即可在任何应用上方发出带原声动画的信号。多人"房间"功能允许朋友之间互相看到对方的信号,而所有房间消息都经过端到端加密——即使信号要绕经公网 Nostr 中继,中继方也只能看到无法解读的密文。这篇文章完整解析 lolPing 房间加密的技术路径:从房间码出发,经过 scrypt 密钥派生、AES-256-GCM 加密,最终通过 Nostr 公网上线,带你看清每一层是如何守护你的 ping 的。
一、为什么房间信号需要端到端加密 🔐
在 lolPing 的Settings → Room页面创建一个房间,会得到类似PING-7KQ4M-2HXTR的房间码。把它发给朋友后,每个人的屏幕上都会出现对方的信号(位置按各自分辨率等比换算)和昵称。
房间有两条网络路径:
- 同一局域网:通过 UDP 直连,走 src/main/lanTransport.ts;
- 不同网络:加密数据包被封装成 Nostr 事件,经由 6 个免费公共中继转发,走 src/main/relayTransport.ts。
第二条路径意味着你的数据要"路过"第三方服务器。如果信号内容明文传输,中继运营方就能看到你 ping 了什么、在哪 ping、你叫什么名字。所以 lolPing 选择了端到端加密:数据在发送方就变成密文,只有持有房间码的人能解开。
二、房间码:一个"敢念出口"的密码
房间码是整套加密体系的根。它的生成规则在 src/shared/roomCode.ts:
- Crockford Base32 编码:字母表
0123456789ABCDEFGHJKMNPQRSTVWXYZ刻意去掉了 I、L、O、U,避免口头传递时 "B/8"、"O/0" 混淆; - 10 位字符:9 位随机 + 1 位校验位;
- Luhn mod 32 校验位:能捕获任何单字符输错,以及大多数两位交换错误——输错一个字母,加入时会直接提示
mistyped而不是静默失败。
解析逻辑 parseRoomCode() 还很宽容:聊天消息里夹带、全角字符、O/I 误输成 0/1 都能识别出来,方便你直接把朋友发的整段话贴进"Join from clipboard"。
三、从房间码到密钥:scrypt 派生的门道 🔑
拿到 10 位标准码后,deriveRoomKeys() 用两步把它变成两套密钥:
第 1 步:scrypt 慢哈希生成主密钥。参数是N = 2^15, r = 8, p = 1,盐值固定为lolping/room/v1,输出 32 字节主密钥。
为什么不用普通哈希?因为中继订阅话题(relay topic)也是从房间码派生的。如果派生函数计算太快,攻击者拿到一个 topic 后就能大规模离线暴力和房间码对账。scrypt 是内存密集型函数(memory-hard),每次尝试都要占用 32 MB 内存,把"猜码"这件事在经济上直接判了死刑。
第 2 步:HKDF-SHA256 把主密钥拆成两个"专钥"。
| 派生标签 | 用途 |
|---|---|
msg | msgKey,AES-256-GCM 的消息加密密钥,永不离开主进程 |
sig-room | relayTopic,64 位十六进制的中继订阅话题 |
这就是"one key, one job"原则:即使其中一个用途的密钥泄露,也不会牵连另一个。而且relayTopic本身就是 64 位随机值的十六进制——没有房间码的人看到它,和看一串雪花噪点没有区别。
四、AES-256-GCM:一个信号包是如何被加密的
每条消息(presence 成员信息、ping 信号、emote 表情、bye 离开通知)在 src/main/roomCrypto.ts 中被seal()打包,格式只有四种字段拼起来:
[ 0x01 格式标记 ][ 12 字节随机 nonce ][ AES-256-GCM 密文 ][ 16 字节 auth tag ]三个关键设计点:
- 每条消息一个全新随机 nonce(
randomBytes(12))。GCM 模式下 nonce 重用是灾难性的,随机 nonce 把这个问题彻底绕开; - 格式标记字节同时作为 AAD(附加认证数据)。接收端
open()会校验这个字节,防止攻击者用"格式合法的别的东西"替换真实包; - GCM 自带完整性校验。密文被篡改哪怕一个比特,16 字节 auth tag 校验就会失败,
open()直接返回null丢弃——加密与防篡改一次到位。
包体有硬上限:MAX_PACKET = 1200字节,更大的包既不会发送也不会被读取,这既是 UDP 友好的尺寸控制,也天然限制了单包体积攻击面。
五、Nostr 中继:只运密文的"公共邮筒" 📡
跨网络时,加密包如何送达?答案是把每个 ≤1200 字节的密封包 base64 编码后,装进一个Nostr 事件里(src/main/nostrEvent.ts):
- kind = 24747:落在 Nostr 的 ephemeral(临时事件)区间 20000–29999。按协议约定,中继只转发、不落盘,会话结束后不留任何历史;
- tag
x= relayTopic:所有成员订阅同一话题,一次 publish 全员可见,成员之间互相看不到 IP; - 每次加入房间都现生成一对 secp256k1 密钥,用 NIP-01 规范对事件签名。签名只是满足中继的"防冒名"要求,真正的安全由房间自己的加密体系负责——所以密钥用完即弃;
- 中继清单:src/main/relays.ts 里的 6 个公共中继是用 tools/relay-probe 从 16 个候选里筛出来的(能接受 kind 24747、30 秒内 5 事件/秒无限流、10 分钟持续连接不掉线)。任何成员只要和另一个成员共享一个可用中继就能互通。代码里还留了一条兼容性铁律:未来版本必须保留旧列表里至少 3 个中继,否则新旧版本互相找不到。
六、隐私边界:中继到底能看到什么?
| 中继能看到 | 中继看不到 | |
|---|---|---|
| 内容 | — | ✅ ping 内容、emote、昵称(全是密文) |
| 身份 | 你的 IP 地址、一个匿名的 64 位房间话题 | ✅ 房间码、成员列表 |
| 行为 | 你何时在发消息 | ✅ 发了什么 |
局域网成员之间只能看到彼此的内网 IP。如果完全不想让数据碰公网,把设置里的Allow internet connections关掉即可,房间退化为纯局域网模式。
七、纵深防御:重放、限速与成员管理 🛡️
加密只是第一层。src/main/roomManager.ts 上还叠了几道闸:
- 序列号防重放:每条消息带
seq序号,配合 replayGuard.ts 识别并丢弃重放的旧包; - 中继限速:共享中继上每位发送者限 5 包/秒、突发 10 包——因为一次 publish 全员可见,公共中继对流量极其敏感;
- 接收限制:设置页可给每个成员单独调"收到的 ping/emote 上限",还能静音单人或整个房间;
- 房间容量 8 人,踢人方式:退出后重建新房间。
八、代码地图:想深挖从哪读起 📖
| 模块 | 文件 | 职责 |
|---|---|---|
| 加密核心 | src/main/roomCrypto.ts | scrypt 派生 + AES-256-GCM 密封/开启 |
| 房间码 | src/shared/roomCode.ts | 生成、校验、容错解析 |
| 消息协议 | src/shared/roomProtocol.ts | presence/ping/emote/bye 定义与校验 |
| 成员管理 | src/main/roomManager.ts | 路由选路、限速、超时踢人 |
| 中继传输 | src/main/relayTransport.ts | 加密包 ↔ Nostr 事件 |
| 中继清单 | src/main/relays.ts | 6 个经过实测的公共中继 |
| 测试 | tests/main/relayRoom.test.ts、tests/shared/roomCode.test.ts | 房间协议与加密测试 |
架构细节(路径选择、超时参数、中继判活策略)在 docs/design.md 有完整论述,单机组一台电脑想体验房间的话,可以用 tools/room-peer 脚本扮演一个随机 ping 的假成员试试。
一句话总结 lolPing 的加密哲学:房间码是唯一秘密——scrypt 让它算不快,HKDF 让它一分两用,AES-256-GCM 让内容密不透风,Nostr ephemeral 事件让密文不留痕。你只需要把 10 个字符告诉朋友,剩下的,数学来处理。
【免费下载链接】lolPing
League of Legends ping wheel for your Windows desktop. Hold Alt, drag, and ping anywhere, with the original animations and sounds.
相关推荐
深度解析Aegis Authenticator安全架构:AES-256-GCM与scrypt如何守护你的2FA密钥
深度解析Aegis Authenticator安全架构:AES 256 GCM与scrypt如何守护你的2FA密钥 Aegis Authenticator 是一
移动开发安全如何无信任地验证 Obsidian Sync 端到端加密:从密钥派生到 AES-256-GCM 解密实操(附 defuddle 提取验证指南)
如何无信任地验证 Obsidian Sync 端到端加密:从密钥派生到 AES 256 GCM 解密实操(附 defuddle 提取验证指南) 本文以 Obsi
后端Apache Pulsar 端到端加密(PIP-4)实战指南:基于 ECDSA/RSA 与 AES-256-GCM 的消息加解密实现
Apache Pulsar 端到端加密(PIP 4)实战指南:基于 ECDSA/RSA 与 AES 256 GCM 的消息加解密实现 本文以 Apache Pu
消息队列流处理后端微服务消息路由
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考