p2p: 组 UUID 并入会话密钥 HKDF salt,防信令中间人(仅 group 路径,旧1v1不变)

This commit is contained in:
Liang Jiaqing committed 2026-11-03 19:34:20 +08:00
1 parent 1438254cda
commit f47403a33a
1 file changed
+7 -4
+7 -4
View File
@@ -103,13 +103,14 @@ def keypair():
sk = X25519PrivateKey.generate()
return sk, _pub_raw(sk.public_key())
def session_key(sk, peer_pub: bytes) -> bytes:
def session_key(sk, peer_pub: bytes, psk: bytes = b"") -> bytes:
"""ECDH + HKDF 派生 32 字节会话密钥。
salt 取两个公钥排序后拼接,双方算出同一个值,且把密钥绑定到本次配对。
psk(共享秘密)也并入 salt:不知 psk 的信令方换公钥做中间人也解不开;空 psk 与旧版完全一致。
"""
mine = _pub_raw(sk.public_key())
salt = b"".join(sorted([mine, peer_pub]))
salt = b"".join(sorted([mine, peer_pub])) + psk
shared = sk.exchange(X25519PublicKey.from_public_bytes(peer_pub))
return HKDF(
algorithm=hashes.SHA256(), length=32, salt=salt, info=b"p2p-ws/v1"
@@ -329,7 +330,7 @@ class P2PSocket:
@classmethod
async def connect(
cls, signal_url: str, room: str, *, direct_timeout=15, peer_timeout=120,
retries=6, stun=True, access_key=DEFAULT_ACCESS_KEY,
retries=6, stun=True, access_key=DEFAULT_ACCESS_KEY, psk=b"",
):
"""连接同一 UUID 的另一个客户端,直连失败自动回退中继。"""
self = cls(
@@ -337,6 +338,7 @@ class P2PSocket:
peer_timeout=peer_timeout, retries=retries, stun=stun,
access_key=access_key,
)
self._psk = psk
try:
await self._connect()
except BaseException:
@@ -356,7 +358,7 @@ class P2PSocket:
{"type": "key", "key": base64.b64encode(public).decode()}
)
key_msg = await self.signal.expect("key")
self._key = session_key(private, base64.b64decode(key_msg["key"]))
self._key = session_key(private, base64.b64decode(key_msg["key"]), getattr(self, "_psk", b""))
self.signal.on_data = self._on_relay_data
self._relay_ready.set()
self.mode = "relay"
@@ -1273,6 +1275,7 @@ class Group:
socket = await P2PSocket.connect(
self.signal_url, room, access_key=self.access_key,
direct_timeout=15, peer_timeout=15,
psk=hashlib.sha256(f"{self.room}:psk".encode()).digest(), # 组 UUID 绑进密钥, 防信令中间人
)
try:
await handler(socket, peer)