Skip to main content

Security model

This page states precisely what the SDK guarantees, so you can decide what your application still needs to handle.

What is protected​

Authentication. Before any application data is exchanged, both peers complete a mutual VaultysID handshake: each signs a fresh challenge with the private key behind its DID. The dialing side also checks that the identity that answered is the DID it dialed.

Confidentiality and integrity. After the handshake, every frame is encrypted and authenticated with a per-session key:

key = SHA-256( "vaultys-peer/v2" ‖ DH(my key, their key) ‖ SHA-256(handshake certificate) )
  • The Diffie-Hellman term means only the two identities can compute the key.
  • The handshake certificate contains fresh nonces from both sides, so every session gets a new key.
  • Frames are sealed with XSalsa20-Poly1305 (NaCl secretbox), each with a random nonce. A frame that fails authentication closes the session.

What this means for the relay. A relay, or anyone else on the path, can forward the handshake, but can't derive the session key without one of the private keys. It can't read messages, inject them, or impersonate either peer. The worst it can do is refuse service.

Authorization. Incoming peers are accepted only if your acceptIncoming policy allows them, and that policy only ever sees a DID that has already been proven. By default, only contacts are accepted.

What isn't (yet)​

Forward secrecy. The session key mixes in static identity keys. If an identity's private key is compromised and an attacker recorded past encrypted traffic, that traffic could be decrypted. Ephemeral key exchange is planned.

Metadata. The relay learns when a (hashed) DID is online and which hashed DIDs try to connect to each other. With WebRTC, peers also learn each other's IP addresses unless traffic goes through TURN.

Storage at rest. Contacts and queued messages are stored in your store as they are. Browser storage is readable by anything running on your origin. If that matters for you, wrap the store with your own encryption.

Your identity's secret. The SDK never stores it. Where and how you keep it is the most important security decision in your app.

Denial of service. A peer you accepted can send you as much as it likes. Rate-limit in your handlers if you accept strangers.

Recommendations​

  • Keep the default contacts-only policy unless your use case needs strangers. If it does, show users who is connecting before accepting.
  • Keep software identity secrets in storage your platform encrypts.
  • Run your own relay (and TURN server) in production. See Relays.
  • Treat message bodies as untrusted input, like any network data. The sender is verified; what they send isn't.