e2ee

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateSessionID added in v0.3.0

func CreateSessionID(userA, deviceA, userB, deviceB string) string

CreateSessionID returns a deterministic session ID for a pair of user:device identifiers.

func GenerateX3DHKeyMaterial added in v0.3.0

func GenerateX3DHKeyMaterial(deviceID string, numOneTimePreKeys int) (*X3DHKeyMaterial, *PublicPreKeyBundle, error)

GenerateX3DHKeyMaterial generates a full set of X3DH keys for a new user/device.

func PerformX3DHInitiator added in v0.3.0

func PerformX3DHInitiator(
	myIdentityKey ed25519.PrivateKey,
	peerBundle *PublicPreKeyBundle,
) (sessionKey, associatedData []byte, ephemeralPub *ecdh.PublicKey, usedOPKID uint32, hasOPK bool, err error)

PerformX3DHInitiator executes the initiator side of X3DH.

func PerformX3DHResponder added in v0.3.0

func PerformX3DHResponder(
	myIdentityKey ed25519.PrivateKey,
	mySignedPreKey *ecdh.PrivateKey,
	myOneTimePreKey *ecdh.PrivateKey,
	senderIdentityPub ed25519.PublicKey,
	senderEphemeralPub *ecdh.PublicKey,
) (sessionKey, associatedData []byte, err error)

PerformX3DHResponder executes the responder side of X3DH.

Types

type DefaultSessionManager added in v0.3.0

type DefaultSessionManager struct {
	// contains filtered or unexported fields
}

DefaultSessionManager manages E2EE session persistence.

func NewSessionManager added in v0.3.0

func NewSessionManager(store KeyStore) *DefaultSessionManager

NewSessionManager creates a new session manager backed by a KeyStore.

type DoubleRatchetSession added in v0.3.0

type DoubleRatchetSession struct {
	// contains filtered or unexported fields
}

DoubleRatchetSession wraps mellium's DHRatchet with message encryption. Each peer maintains one of these for every active conversation.

func NewDoubleRatchetInitiator added in v0.3.0

func NewDoubleRatchetInitiator(sessionKey []byte, ephemeralPriv *ecdh.PrivateKey, peerSPKPub *ecdh.PublicKey) (*DoubleRatchetSession, error)

NewDoubleRatchetInitiator creates a session for the initiator (Alice). After X3DH, Alice uses the shared session key as the root key and her ephemeral key as the initial ratchet private key.

Flow: Alice calls Step(Bob's SPK public) to derive the first send key.

func NewDoubleRatchetResponder added in v0.3.0

func NewDoubleRatchetResponder(sessionKey []byte, spkPriv *ecdh.PrivateKey) (*DoubleRatchetSession, error)

NewDoubleRatchetResponder creates a session for the responder (Bob). After X3DH, Bob uses the shared session key as the root key and generates a new ratchet key pair. Bob waits for Alice's first message before stepping.

func (*DoubleRatchetSession) Decrypt added in v0.3.0

func (s *DoubleRatchetSession) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt decrypts a ciphertext message using the current receiving key.

func (*DoubleRatchetSession) Encrypt added in v0.3.0

func (s *DoubleRatchetSession) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts a plaintext message using the current sending key. Uses XChaCha20-Poly1305 for AEAD encryption.

func (*DoubleRatchetSession) Ratchet added in v0.3.0

func (s *DoubleRatchetSession) Ratchet(peerPub *ecdh.PublicKey) error

Ratchet advances the ratchet state with the peer's current DH public key. Returns new send and recv message keys.

func (*DoubleRatchetSession) RecvKey added in v0.3.0

func (s *DoubleRatchetSession) RecvKey() []byte

RecvKey returns the current receiving key (useful for session serialization).

func (*DoubleRatchetSession) SendKey added in v0.3.0

func (s *DoubleRatchetSession) SendKey() []byte

SendKey returns the current sending key (useful for session serialization).

type EncryptedMessage added in v0.3.0

type EncryptedMessage struct {
	SenderID   string `json:"sender_id"`
	ReceiverID string `json:"receiver_id"`
	Ciphertext []byte `json:"ciphertext"`
	Header     []byte `json:"header"` // Double Ratchet header (DH public key, message counter, etc.)
	Timestamp  int64  `json:"timestamp"`
}

EncryptedMessage represents the wire format for an E2EE message. It contains the encrypted ciphertext and the ratchet header needed by the receiver to derive the correct decryption key.

func Deserialize added in v0.3.0

func Deserialize(data []byte) (*EncryptedMessage, error)

Deserialize decodes a JSON payload into an EncryptedMessage.

func (*EncryptedMessage) Serialize added in v0.3.0

func (m *EncryptedMessage) Serialize() ([]byte, error)

Serialize encodes the encrypted message to JSON for transport.

type KeyStore added in v0.3.0

type KeyStore interface {
	// Identity Keys (public only, for server-side storage)
	SaveIdentityPublicKey(ctx context.Context, userID string, pubKey []byte) error
	LoadIdentityPublicKey(ctx context.Context, userID string) ([]byte, error)

	// PreKey Bundles (public bundle for X3DH)
	SavePreKeyBundle(ctx context.Context, userID string, bundle *PublicPreKeyBundle) error
	LoadPreKeyBundle(ctx context.Context, userID string) (*PublicPreKeyBundle, error)
	ConsumeOneTimePreKey(ctx context.Context, userID string) error

	// Session State (ratchet state, stored client-side)
	SaveSession(ctx context.Context, sessionID string, state []byte) error
	LoadSession(ctx context.Context, sessionID string) ([]byte, error)
}

KeyStore defines the interface for persistence of E2EE key material. The server stores ONLY public keys and prekey bundles. Private keys are stored ONLY on the client side.

type PublicPreKeyBundle added in v0.3.0

type PublicPreKeyBundle struct {
	DeviceID       string                     `json:"device_id"`      // Unique ID for the device publishing this bundle
	IdentityKey    ed25519.PublicKey          `json:"identity_key"`   // Ed25519 identity public key
	SignedPreKey   *ecdh.PublicKey            `json:"-"`              // X25519 signed prekey (public)
	SPKSignature   []byte                     `json:"spk_signature"`  // Ed25519 signature of the SPK
	SPKCreatedAt   int64                      `json:"spk_created_at"` // Timestamp when the SPK was generated
	OneTimePreKeys map[uint32]*ecdh.PublicKey `json:"-"`              // X25519 one-time prekeys (indexed)

	// Serialized forms for JSON transport
	SignedPreKeyBytes   []byte            `json:"signed_prekey"`
	OneTimePreKeysBytes map[uint32][]byte `json:"one_time_prekeys,omitempty"`
}

PublicPreKeyBundle contains the public keys a user (per device) publishes to the server for asynchronous X3DH key agreement. This is the Signal Protocol PreKeyBundle.

func (*PublicPreKeyBundle) MarshalKeys added in v0.3.0

func (b *PublicPreKeyBundle) MarshalKeys()

MarshalKeys populates the byte fields from the key objects for transport.

func (*PublicPreKeyBundle) UnmarshalKeys added in v0.3.0

func (b *PublicPreKeyBundle) UnmarshalKeys() error

UnmarshalKeys populates the key objects from the byte fields after transport.

type SQLKeyStore added in v0.3.0

type SQLKeyStore struct {
	// contains filtered or unexported fields
}

SQLKeyStore implements the KeyStore interface using a SQL database. The server uses this to store public identity keys and prekey bundles. Clients use this to store session state.

func NewSQLKeyStore added in v0.3.0

func NewSQLKeyStore(backend *db.Backend, prefix string) (*SQLKeyStore, error)

NewSQLKeyStore creates a new SQL-based key store.

func (*SQLKeyStore) ConsumeOneTimePreKey added in v0.3.0

func (s *SQLKeyStore) ConsumeOneTimePreKey(ctx context.Context, userID string) error

func (*SQLKeyStore) LoadIdentityPublicKey added in v0.3.0

func (s *SQLKeyStore) LoadIdentityPublicKey(ctx context.Context, userID string) ([]byte, error)

func (*SQLKeyStore) LoadPreKeyBundle added in v0.3.0

func (s *SQLKeyStore) LoadPreKeyBundle(ctx context.Context, userID string) (*PublicPreKeyBundle, error)

func (*SQLKeyStore) LoadSession added in v0.3.0

func (s *SQLKeyStore) LoadSession(ctx context.Context, sessionID string) ([]byte, error)

func (*SQLKeyStore) SaveIdentityPublicKey added in v0.3.0

func (s *SQLKeyStore) SaveIdentityPublicKey(ctx context.Context, userID string, pubKey []byte) error

func (*SQLKeyStore) SavePreKeyBundle added in v0.3.0

func (s *SQLKeyStore) SavePreKeyBundle(ctx context.Context, userID string, bundle *PublicPreKeyBundle) error

func (*SQLKeyStore) SaveSession added in v0.3.0

func (s *SQLKeyStore) SaveSession(ctx context.Context, sessionID string, state []byte) error

type Session added in v0.3.0

type Session struct {
	ID        string    `json:"id"`
	UserA     string    `json:"user_a"`
	UserB     string    `json:"user_b"`
	State     []byte    `json:"state"` // Serialized Double Ratchet state
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Session tracks the E2EE state between two users/devices.

type X3DHKeyMaterial added in v0.3.0

type X3DHKeyMaterial struct {
	IdentityKey    ed25519.PrivateKey // Ed25519 identity key (long-lived)
	SignedPreKey   *ecdh.PrivateKey   // X25519 signed prekey (medium-lived)
	SPKSignature   []byte             // Ed25519 signature of the SPK public key
	OneTimePreKeys []*ecdh.PrivateKey // X25519 one-time prekeys (single-use)
}

X3DHKeyMaterial holds all the private key material for a user's X3DH identity. This is stored ONLY on the client side. Never on the server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL