Skip to main content

End-to-end encryption utilities for SyftBox using X3DH protocol

Project description

SyftCrypto: End-to-End Encryption for SyftBox

SyftCrypto provides cryptography utilities for SyftBox, implementing a simplified X3DH protocol for secure, asynchronous communication between federated computation participants.

Overview

SyftCrypto enables secure message exchange in SyftBox using a custom implementation of the X3DH (Extended Triple Diffie-Hellman) protocol. This implementation provides forward secrecy, mutual authentication, and asynchronous communication capabilities tailored for federated computation use cases.

x3dh-overview

Key Features

  • Forward Secrecy: Fresh ephemeral keys per message prevent retroactive decryption
  • Mutual Authentication: Signed prekeys provide cryptographic proof of identity
  • Asynchronous Communication: DID documents enable offline key exchange
  • Deniability: No permanent signatures on message contents (only on prekeys)
  • Simplified Protocol: 2 DH operations instead of 4 for better performance
  • Standards-Based: Uses W3C DID documents and JWK key formats

Architecture

The protocol flow consists of four main phases:

Phase 0: Keys Bootstrapping & Publishing

Both Alice and Bob generate their cryptographic identities:

  1. Generate Identity Key (Ed25519) for signing prekeys
  2. Generate Signed PreKey (X25519) for key exchange
  3. Sign the prekey with the identity key
  4. Save private keys securely to ~/.syftbox/{hash}/pvt.jwks.json
  5. Create DID document at {datasite}/public/did.json

Phase 1: Alice Sends Encrypted Message

  1. Download Bob's DID document to get his signed prekey
  2. Generate ephemeral key pair for this message
  3. Perform custom X3DH key exchange:
    • DH1 = DH(SPK_alice, SPK_bob) - Authentication
    • DH2 = DH(EK_alice, SPK_bob) - Forward secrecy
  4. Derive shared secret: shared_key = HKDF(DH1 || DH2)
  5. Encrypt message using AES-GCM with shared key
  6. Upload encrypted payload: {ek, iv, ciphertext, tag, sender, receiver}

Phase 2: Bob Decrypts Message

  1. Download encrypted payload from Alice
  2. Load Alice's DID document to get her signed prekey
  3. Reconstruct Alice's ephemeral key from payload
  4. Perform same X3DH operations to derive identical shared key
  5. Decrypt message using AES-GCM

Phase 3: Secure Bidirectional Communication

The same process enables Bob to send encrypted responses to Alice, establishing secure bidirectional communication.

Installation

pip install syft-crypto

Quick Start

1. Bootstrap User Keys

from syft_crypto import bootstrap_user, ensure_bootstrap
from syft_core import Client

# Load SyftBox client
client = Client.load()

# Generate keys and DID document
bootstrap_user(client)

# Or ensure keys exist (generates if needed)
client = ensure_bootstrap()

2. Encrypt a Message

from syft_crypto import encrypt_message

# Encrypt message for recipient
encrypted_payload = encrypt_message(
    message="Hello Bob!",
    to="bob@example.com", 
    client=client,
    verbose=True
)

# encrypted_payload is ready to send via SyftBox

3. Decrypt a Message

from syft_crypto import decrypt_message

# Decrypt received payload
plaintext = decrypt_message(
    payload=encrypted_payload,
    client=client,
    verbose=True
)

print(f"Decrypted: {plaintext}")

API Reference

Core Functions

bootstrap_user(client: Client, force: bool = False) -> bool

Generate X3DH keypairs and create DID document for a user.

Parameters:

  • client: SyftBox client instance
  • force: If True, regenerate keys even if they exist

Returns:

  • bool: True if keys were generated, False if they already existed

encrypt_message(message: str, to: str, client: Client, verbose: bool = False) -> EncryptedPayload

Encrypt message using X3DH protocol.

Parameters:

  • message: The plaintext message to encrypt
  • to: Email of the recipient
  • client: SyftBox client instance
  • verbose: If True, log status messages

Returns:

  • EncryptedPayload: The encrypted message payload

decrypt_message(payload: EncryptedPayload, client: Client, verbose: bool = False) -> str

Decrypt message using X3DH protocol.

Parameters:

  • payload: The encrypted message payload
  • client: SyftBox client instance
  • verbose: If True, log status messages

Returns:

  • str: The decrypted plaintext message

Data Structures

EncryptedPayload

class EncryptedPayload(BaseModel):
    ek: bytes          # Ephemeral key
    iv: bytes          # Initialization vector
    ciphertext: bytes  # Encrypted message
    tag: bytes         # Authentication tag
    sender: str        # Sender's email
    receiver: str      # Receiver's email  
    version: str       # Protocol version

Utility Functions

DID Document Management

  • create_x3dh_did_document(): Create DID document with X3DH keys
  • get_did_document(): Load user's DID document
  • save_did_document(): Save DID document to appropriate location
  • get_public_key_from_did(): Extract public key from DID document

Key Storage

  • save_private_keys(): Save private keys securely as JWKs
  • load_private_keys(): Load private keys from JWK storage
  • keys_exist(): Check if private keys exist
  • key_to_jwk(): Convert public key to JWK format

File Locations

Private Keys

Private keys are stored securely at:

~/.syftbox/{sha256(server::email)[:8]}/pvt.jwks.json

Example format:

{
  "identity_key": {
    "kty": "OKP",
    "crv": "Ed25519", 
    "x": "adfasfxxx342",
    "d": "1231adfer334"
  },
  "signed_prekey": {
    "kty": "OKP",
    "crv": "X25519",
    "x": "X-HElnE4yZc0bMhAAqkyhAn4", 
    "d": "GBiBZnLVzEiZ2qN5T7adfaWQ"
  }
}

Public Keys (DID Documents)

Public keys are published as W3C DID documents at:

{datasite}/public/did.json

Example DID document:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1", 
    "https://w3id.org/security/suites/x25519-2020/v1"
  ],
  "id": "did:web:syftbox.net:alice%40example.com",
  "verificationMethod": [{
    "id": "did:web:syftbox.net:alice%40example.com#identity-key",
    "type": "Ed25519VerificationKey2020",
    "controller": "did:web:syftbox.net:alice%40example.com",
    "publicKeyJwk": {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "oAXB82sUeKHqjKhqGOjsoed1OfksDD9rcZUyOjDnYrs",
      "kid": "identity-key",
      "use": "sig"
    }
  }],
  "keyAgreement": [{
    "id": "did:web:syftbox.net:alice%40example.com#signed-prekey", 
    "type": "X25519KeyAgreementKey2020",
    "controller": "did:web:syftbox.net:alice%40example.com",
    "publicKeyJwk": {
      "kty": "OKP",
      "crv": "X25519",
      "x": "X-HElnE48aUIpBjfyZesdT2gtM4a8c0bMhAAqkyhAn4",
      "kid": "signed-prekey", 
      "use": "enc",
      "signature": "b4XuL6T8SbLyFrNrhK18eB0_mU1D6CQ"
    }
  }]
}

Security Properties

Cryptographic Guarantees

  • Forward Secrecy: Fresh ephemeral keys prevent retroactive decryption if long-term keys are compromised
  • Mutual Authentication: Both parties' signed prekeys provide cryptographic proof of identity
  • Deniability: Message contents aren't permanently signed, providing plausible deniability
  • Asynchronous Security: Recipients don't need to be online during key exchange

Key Management

  • Private keys stored in secure local directories using SHA-256 hashed paths
  • Public keys published in standardized W3C DID documents
  • Identity keys used only for signing prekeys, never for direct encryption
  • Ephemeral keys generated fresh for each message

Protocol Security

The custom X3DH implementation uses:

  • 2 DH operations instead of full X3DH's 4 operations for better performance
  • HKDF-SHA256 for key derivation with domain separation
  • AES-GCM for authenticated encryption
  • Ed25519 signatures for prekey authentication
  • X25519 for Elliptic Curve Diffie-Hellman operations

Simplified vs Full X3DH Trade-offs

Feature Full X3DH SyftCrypto
DH Operations 4 2
One-time PreKeys L
Identity Key DH L
Forward Secrecy
Mutual Authentication
Performance Slower Faster
Key Management Complex Simplified

The simplified approach maintains core security properties while reducing complexity and improving performance for SyftBox's federated computation use cases.

Dependencies

  • cryptography: Core cryptographic primitives
  • jwcrypto: JSON Web Key handling
  • pydantic: Data validation and serialization
  • syft-core: SyftBox client integration
  • loguru: Structured logging

Development

Running Tests

# Run all tests
pytest tests/

# Run with coverage
pytest tests/ -v --cov=syft_crypto --cov-report=term-missing

# Run specific test categories
pytest tests/x3dh_encryption_test.py  # Core encryption tests
pytest tests/bootstrap_test.py         # Key bootstrapping tests
pytest tests/crypto_security_test.py   # Security property tests
pytest tests/key_management_test.py    # Key lifecycle tests
pytest tests/message_integrity_test.py # Message integrity tests
pytest tests/protocol_security_test.py # Protocol security tests
pytest tests/attack_resilience_test.py # Attack resistance tests

Project Structure

syft-crypto/
  ├── docs/                                   # Documentation and diagrams
  ├── syft_crypto/                           # Main package directory
  │   ├── __init__.py                        # Package initialization and public API exports
  │   ├── did_utils.py                       # DID document management and utilities
  │   ├── key_storage.py                     # Secure private key storage and JWK handling
  │   ├── x3dh_bootstrap.py                  # User key generation and bootstrapping
  │   └── x3dh.py                           # Core X3DH encryption/decryption protocol
  ├── tests/                                 # Test suite for all functionality
  ├── pyproject.toml                         # Project configuration and dependencies
  └── README.md                             # Documentation with API reference and examples

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

This project is part of the OpenMined ecosystem. Please refer to the main repository for licensing information.

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

syft_crypto-0.1.0.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

syft_crypto-0.1.0-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

Details for the file syft_crypto-0.1.0.tar.gz.

File metadata

  • Download URL: syft_crypto-0.1.0.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for syft_crypto-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3fde15f73a9ddab3abb8d6aeaa7616f66e0b244ae32e5f355b6baec21db855b0
MD5 3b03064fd3e62033b212f0ea2888a616
BLAKE2b-256 8deb946aed97f086ce344957b411f095a4a218c23536b88a33866af6a13213ac

See more details on using hashes here.

File details

Details for the file syft_crypto-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: syft_crypto-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for syft_crypto-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df5129dd8e9619f2602b00604e62cd9280eef8727c05462ed7fc84c0403f21c0
MD5 ee9214f611459025023900a5bd9c5312
BLAKE2b-256 7e85e37a9a84f2812ae51c3ca126ac9b4d019f20dcf18651b6034819817c5cb2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page