aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/src/meshbay_common/crypto.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common/crypto.py')
-rw-r--r--packages/meshbay-common/src/meshbay_common/crypto.py92
1 files changed, 0 insertions, 92 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/crypto.py b/packages/meshbay-common/src/meshbay_common/crypto.py
index e537500..8fb80f8 100644
--- a/packages/meshbay-common/src/meshbay_common/crypto.py
+++ b/packages/meshbay-common/src/meshbay_common/crypto.py
@@ -41,25 +41,6 @@ def generate_gek() -> bytes:
"""Generate a fresh 256-bit Group Encryption Key."""
return ChaCha20Poly1305.generate_key()
-def chunk_key(gek: bytes, file_hash: bytes, chunk_index: int) -> bytes:
- """Derive a per-chunk encryption key from the GEK (deterministic)."""
- return HKDF(
- algorithm=hashes.SHA256(),
- length=32,
- salt=None,
- info=b"file:" + file_hash + b":chunk:" + chunk_index.to_bytes(4, "big"),
- ).derive(gek)
-
-def encrypt_chunk(key: bytes, plaintext: bytes) -> tuple[bytes, bytes]:
- """Encrypt plaintext with ChaCha20-Poly1305. Returns (nonce, ciphertext)."""
- nonce = os.urandom(12)
- ct = ChaCha20Poly1305(key).encrypt(nonce, plaintext, None)
- return nonce, ct
-
-def decrypt_chunk(key: bytes, nonce: bytes, ciphertext: bytes) -> bytes:
- """Decrypt ciphertext. Raises InvalidTag on authentication failure."""
- return ChaCha20Poly1305(key).decrypt(nonce, ciphertext, None)
-
def file_hash(path_or_bytes) -> bytes:
"""Compute blake3 hash of a file (bytes or path-like)."""
if isinstance(path_or_bytes, (str, bytes)) and not isinstance(path_or_bytes, bytes):
@@ -73,58 +54,6 @@ def file_hash(path_or_bytes) -> bytes:
# ── GEK wrapping (ECIES-like) ─────────────────────────────────────────────────
-GEK_WRAP_INFO = b"meshbay:gek_wrap:v1"
-
-def wrap_gek(gek: bytes, pk_recipient: bytes) -> dict:
- """
- Wrap a GEK for a recipient using ephemeral X25519 + HKDF + ChaCha20-Poly1305.
-
- Protocol:
- 1. Generate ephemeral (sk_eph, pk_eph)
- 2. shared = X25519(sk_eph, pk_recipient)
- 3. wrap_key = HKDF(shared, salt=pk_eph, info=GEK_WRAP_INFO)
- 4. wrapped = ChaCha20-Poly1305(wrap_key).encrypt(nonce, gek, aad=pk_recipient)
-
- The hub stores {pk_eph, nonce, wrapped} — opaque, cannot decrypt.
- """
- sk_eph = X25519PrivateKey.generate()
- pk_eph_raw = pk_to_raw(sk_eph.public_key())
-
- shared = sk_eph.exchange(X25519PublicKey.from_public_bytes(pk_recipient))
- wrap_key = HKDF(
- algorithm=hashes.SHA256(), length=32,
- salt=pk_eph_raw, info=GEK_WRAP_INFO,
- ).derive(shared)
-
- nonce = os.urandom(12)
- wrapped = ChaCha20Poly1305(wrap_key).encrypt(nonce, gek, pk_recipient)
-
- return {
- "pk_eph_b64": base64.b64encode(pk_eph_raw).decode(),
- "nonce_b64": base64.b64encode(nonce).decode(),
- "wrapped_b64": base64.b64encode(wrapped).decode(),
- }
-
-def unwrap_gek(bundle: dict, sk_recipient: bytes, pk_recipient: bytes) -> bytes:
- """
- Unwrap a GEK bundle using the recipient's X25519 private key.
- Raises InvalidTag if the key is wrong or the bundle was tampered.
- """
- pk_eph_raw = base64.b64decode(bundle["pk_eph_b64"])
- nonce = base64.b64decode(bundle["nonce_b64"])
- wrapped = base64.b64decode(bundle["wrapped_b64"])
-
- shared = X25519PrivateKey.from_private_bytes(sk_recipient).exchange(
- X25519PublicKey.from_public_bytes(pk_eph_raw)
- )
- wrap_key = HKDF(
- algorithm=hashes.SHA256(), length=32,
- salt=pk_eph_raw, info=GEK_WRAP_INFO,
- ).derive(shared)
-
- return ChaCha20Poly1305(wrap_key).decrypt(nonce, wrapped, pk_recipient)
-
-
GEK_WRAP_INFO_AES = b"meshbay:gek_wrap:v1:aes"
def wrap_gek_aes(gek: bytes, pk_recipient: bytes) -> dict:
@@ -220,24 +149,3 @@ def decrypt_keystore(iv: bytes, ciphertext: bytes, tag: bytes, key: bytes) -> by
"""Decrypt keystore blob. Raises on authentication failure."""
dec = Cipher(algorithms.AES(key), modes.GCM(iv, tag)).decryptor()
return dec.update(ciphertext) + dec.finalize()
-
-# ── Chunk signing ─────────────────────────────────────────────────────────────
-
-def sign_chunk(sk_node: Ed25519PrivateKey, chunk_index: int,
- nonce: bytes, ct_hash: bytes) -> bytes:
- """
- Sign chunk metadata. Payload: chunk_index || nonce || ct_hash.
-
- Despite the name, this no longer signs file chunks — Phase 9.15 dropped per-chunk
- signatures on the WebRTC path and 2026-09-03 dropped the QUIC copy that had been
- left behind. Its one caller is `GroupIndex.serialize()`, which signs a whole index
- envelope under the pseudo-index `INDEX_CHUNK`.
- """
- payload = chunk_index.to_bytes(4, "big") + nonce + ct_hash
- return sk_node.sign(payload)
-
-def verify_chunk_signature(pk_node: Ed25519PublicKey, chunk_index: int,
- nonce: bytes, ct_hash: bytes, signature: bytes) -> None:
- """Verify chunk signature. Raises InvalidSignature on failure."""
- payload = chunk_index.to_bytes(4, "big") + nonce + ct_hash
- pk_node.verify(signature, payload)