Skip to main content
AgentVault provides end-to-end encryption for all agent-owner communications. The server never sees plaintext — all encryption and decryption happens client-side. This guide covers the cryptographic primitives, key handling requirements, and forward secrecy guarantees that every integration must follow.
AgentVault’s crypto library (@agentvault/crypto) implements all of these requirements. If you are building a custom integration, follow this guide to ensure compatibility.

Cryptographic Primitives

AgentVault uses a carefully chosen set of modern primitives via libsodium.
PurposeAlgorithmNotes
Symmetric encryptionXChaCha20-Poly1305AEAD cipher with 192-bit nonce
Key exchangeX25519 (Curve25519 ECDH)Used in X3DH handshake
Digital signaturesEd25519Identity keys, message authentication
HashingBLAKE2bInvite token hashing, KDF inputs
Key derivationHKDF-SHA-256Ratchet chain key derivation
AgentVault does not use AES-GCM. The 192-bit nonce in XChaCha20-Poly1305 eliminates nonce reuse risk that plagues AES-GCM’s 96-bit nonce, which is critical for high-throughput messaging where random nonce collisions become statistically significant.

Key Exchange: X3DH

AgentVault uses the Extended Triple Diffie-Hellman (X3DH) protocol to establish shared secrets between an owner and an agent device. The handshake occurs during device enrollment.
1

Identity key generation

Each device generates a long-term Ed25519 identity key pair stored in OS secure storage (Keychain on iOS, Keystore on Android, expo-secure-store cross-platform).
2

Ephemeral key generation

The initiating device generates a one-time X25519 ephemeral key pair for the handshake.
3

Triple DH computation

Three DH computations produce the shared secret:
  • DH(identity_A, ephemeral_B)
  • DH(ephemeral_A, identity_B)
  • DH(ephemeral_A, ephemeral_B)
The results are concatenated and passed through HKDF to derive the initial root key.
4

Double Ratchet initialization

The shared secret seeds the Double Ratchet algorithm for ongoing message encryption.
AgentVault’s X3DH implementation uses synchronous enrollment (both parties are online), so signed prekeys and one-time prekeys are not required. This is acceptable for the agent use case where devices enroll in real-time.

Double Ratchet Protocol

After the X3DH handshake, all messages are encrypted using the Double Ratchet algorithm, which provides forward secrecy and break-in recovery.

How It Works

The Double Ratchet combines two ratcheting mechanisms:
  1. Symmetric-key ratchet (chain keys) — Derives a new message key for each message using HKDF. Old keys are deleted after use, providing forward secrecy.
  2. Diffie-Hellman ratchet — Periodically performs a new DH key exchange to provide break-in recovery. If a key is compromised, future messages remain secure after the next DH ratchet step.

Ratchet Advancement

Root Key ──► DH Ratchet Step ──► New Chain Key

                                      ├──► Message Key 1 (deleted after use)
                                      ├──► Message Key 2 (deleted after use)
                                      └──► Message Key 3 (deleted after use)
The ratchet must advance on every message. Reusing a message key breaks forward secrecy and exposes all messages encrypted under that key.

Device Key Handling

Proper key storage is critical to the security model.

Requirements

RequirementImplementation
Private key storageOS secure storage (Keychain, Keystore, expo-secure-store)
Key loggingNever log private key material under any circumstances
Session stateEncrypt local ratchet state at rest
Key deletionDelete message keys immediately after decryption
Debug loggingDisable all crypto debug logs in production builds

Key Types and Lifecycle

  • Generated once per device during enrollment
  • Stored permanently in OS secure storage
  • Used to sign messages and derive DH shared secrets
  • Survives app updates; lost only on device wipe or explicit revocation
  • Generated during X3DH handshake
  • Used once to establish the initial shared secret
  • Deleted after the Double Ratchet is initialized
  • Derived from the root key via HKDF after each DH ratchet step
  • Used to derive individual message keys
  • Advanced (replaced) after each message
  • Derived from the current chain key
  • Used to encrypt/decrypt exactly one message
  • Deleted immediately after use to ensure forward secrecy

Library Choices

The @agentvault/crypto npm package provides a complete implementation of AgentVault’s cryptographic protocol.
npm install @agentvault/crypto
import { DoubleRatchet } from "@agentvault/crypto";

// After X3DH handshake, initialize the ratchet
const ratchet = DoubleRatchet.initSender(sharedSecret, remotePublicKey);

// Encrypt a message
const { header, ciphertext } = await ratchet.encrypt(
  new TextEncoder().encode("Hello, agent!")
);

// Send header + ciphertext to the server (server sees only ciphertext)

Custom Implementations

If you are building a custom integration in a language other than TypeScript, use any libsodium binding that provides:
  • crypto_aead_xchacha20poly1305_ietf_encrypt / decrypt
  • crypto_scalarmult (X25519)
  • crypto_sign_ed25519 keypair generation and signing
  • crypto_generichash (BLAKE2b)
  • crypto_kdf_hkdf_sha256_extract / expand (or equivalent HKDF)
from nacl.public import PrivateKey, Box
from nacl.signing import SigningKey
from nacl.utils import random

# Generate identity key pair
signing_key = SigningKey.generate()
verify_key = signing_key.verify_key

# Generate X25519 key pair for DH
private_key = PrivateKey.generate()
public_key = private_key.public_key

# XChaCha20-Poly1305 encryption via Box
box = Box(private_key, remote_public_key)
ciphertext = box.encrypt(plaintext)

Forward Secrecy Guarantees

AgentVault’s protocol provides two levels of forward secrecy:
PropertyMechanismGuarantee
Forward secrecySymmetric ratchet (chain key advancement)Compromising a message key does not reveal past messages
Break-in recoveryDH ratchet (periodic re-keying)Compromising a long-term key does not reveal future messages after the next DH step

Ensuring Forward Secrecy in Your Integration

  1. Delete message keys after use. Never cache or persist decrypted message keys.
  2. Advance the ratchet on every message. Skipping ratchet steps weakens forward secrecy.
  3. Re-key on member removal. When a device is revoked, all remaining sessions must re-key.
  4. Verify epoch consistency. Ensure both parties agree on the current ratchet state.

Validation Tests

Any custom cryptographic integration should pass these test categories before deployment.
CategoryTest
Replay attacksReject messages with previously seen nonces or sequence numbers
Out-of-order deliveryCorrectly decrypt messages received out of order (within the skip window)
Corrupt ciphertextReject tampered ciphertext (Poly1305 MAC verification failure)
Device revocationRefuse to encrypt/decrypt after a device has been revoked
Key deletionVerify that message keys are not recoverable after decryption
Ratchet advancementConfirm that each message produces a unique ciphertext even for identical plaintext

Operational Safeguards

These safeguards are mandatory for production deployments.
SafeguardRationale
Disable debug logs in productionCrypto debug logs may leak key material or plaintext
Validate JWT before any DB accessPrevents unauthorized access to encrypted message store
Rate limit enrollment endpointsPrevents brute-force attacks on the X3DH handshake (5 attempts per IP per 10 minutes)
Use BYTEA columns for crypto materialNever store keys or ciphertext as TEXT — binary storage prevents encoding issues
Generic error messagesAuth and enrollment failures must not leak information about valid identities