Encrypt remote transport with post-quantum session keys
Testing / test (push) Successful in 21s
Package Extension / package-extension (push) Successful in 18s
Build & Publish Package / publish (push) Successful in 29s

This commit is contained in:
2026-05-05 10:49:38 +02:00
parent 9096efd36a
commit 94c87e244b
8 changed files with 174 additions and 18 deletions
+34 -4
View File
@@ -13,6 +13,7 @@ import os
import re
import socket
import struct
import sys
import uuid
from dataclasses import dataclass
from multiprocessing.connection import Client as PipeClient
@@ -318,22 +319,51 @@ def _send_remote(endpoint: str, msg: dict, private_key=None) -> bytes | None:
except (IndexError, ValueError):
pass
pq_shared_secret = None
if nonce_hex and private_key is not None:
from browser_cli.auth import PQ_KEX_ALG, pq_kex_client_encapsulate, sign, public_key_hex
from browser_cli.auth import PQ_KEX_ALG, pq_encrypt, pq_kex_client_encapsulate, sign, public_key_hex
nonce = bytes.fromhex(nonce_hex)
clean_msg = {k: v for k, v in msg.items() if k not in {"token", "pubkey", "sig", "pq_kex"}}
pq_shared_secret = None
clean_msg = {k: v for k, v in msg.items() if k not in {"token", "pubkey", "sig", "pq_kex", "encrypted"}}
kex = challenge.get("pq_kex") if isinstance(challenge, dict) else None
if isinstance(kex, dict) and kex.get("alg") == PQ_KEX_ALG and kex.get("public_key"):
ciphertext_hex, pq_shared_secret = pq_kex_client_encapsulate(str(kex["public_key"]))
clean_msg["pq_kex"] = {"alg": PQ_KEX_ALG, "ciphertext": ciphertext_hex}
else:
sys.stderr.write(
"** WARNING: connection is not using a post-quantum key exchange algorithm.\n"
"** This session may be vulnerable to store now, decrypt later attacks.\n"
)
sig = sign(private_key, nonce, clean_msg, pq_shared_secret)
msg = {**clean_msg, "pubkey": public_key_hex(private_key), "sig": sig.hex()}
if pq_shared_secret is not None:
encrypted = pq_encrypt(pq_shared_secret, "request", json.dumps(clean_msg).encode("utf-8"))
msg = {
"id": clean_msg.get("id"),
"user_agent": clean_msg.get("user_agent"),
"pubkey": public_key_hex(private_key),
"sig": sig.hex(),
"pq_kex": clean_msg["pq_kex"],
"encrypted": encrypted,
}
else:
sys.stderr.write(
"** WARNING: connection is not using a post-quantum key exchange algorithm.\n"
"** This session may be vulnerable to store now, decrypt later attacks.\n"
)
payload = json.dumps(msg).encode("utf-8")
framed = struct.pack("<I", len(payload)) + payload
sock.sendall(framed)
return _recv_all(sock)
response = _recv_all(sock)
if response is not None and pq_shared_secret is not None:
try:
from browser_cli.auth import pq_decrypt
envelope = json.loads(response)
if isinstance(envelope, dict) and "encrypted" in envelope:
return pq_decrypt(pq_shared_secret, "response", envelope["encrypted"])
except Exception as e:
raise BrowserNotConnected(f"Cannot decrypt post-quantum remote response: {e}") from e
return response
def _auto_route_remote(endpoint: str, key=None) -> str | None: