Skip to content

Cloud Sync

ZestSSH Cloud Sync keeps your SSH connections, identities, and configuration synchronized across all your devices with end-to-end encryption. The server never sees your plaintext data.

Requires: Cloud Sync entitlement (included in the Cloud Sync add-on or the Bundle).

Cloud Sync uses a zero-knowledge encryption design. See Zero-Knowledge Encryption for the full technical details. The key points:

  • Your sync password is used to derive a Master Encryption Key (MEK) via Argon2id (64 MB, 3 iterations, 4 parallelism).
  • A random Data Encryption Key (DEK) encrypts the actual data with AES-256-GCM.
  • The DEK is wrapped by the MEK and stored encrypted on the server.
  • A separate recovery key wraps the DEK independently for account recovery.
  • The server only stores encrypted blobs, salts, and verification hashes.
DataSyncedNotes
ConnectionsYesHost, port, label, group, protocol, keep-alive, startup command, WoL settings, environment variables, agent forwarding, sort order
IdentitiesYesUsername, auth method, key type, public key fingerprint/data, default flag
Identity secretsYesPasswords and private keys (encrypted in the sync blob, also written to secure storage on restore)
Connection groupsYesName, sort order, expanded state
Known hostsYesHost, port, key type, fingerprint, public key, first/last seen timestamps
SnippetsYesLabel, command, category, confirm-before-run flag, default flag, sort order
Port forward rulesYesConnection ID, type, bind address/port, remote host/port, auto-start flag, label

The sync blob includes a schema_version field (currently 5) and a synced_at timestamp. This allows future schema migrations without breaking existing synced data.

DataReason
Terminal transcripts / session recordingsToo large; device-specific
Automation history / audit logsDevice-specific execution records
App settings and preferencesTheme choices, font sizes, UI preferences are personal to each device
Terminal theme customizationsStored locally in SharedPreferences
Auto-backup passwordsDevice-specific secure storage
  1. Sign in with Google or Apple (Firebase Auth).
  2. ZestSSH verifies Cloud Sync entitlement with the server.
  3. Choose a sync password (minimum length enforced).
  4. A random DEK is generated.
  5. The MEK is derived from the password + random salt.
  6. A recovery key is generated and displayed (save it securely).
  7. The DEK is wrapped with both the MEK and recovery KEK.
  8. All local data is encrypted and pushed.
  1. Gather all data from the 6 DAOs + secure storage secrets.
  2. Encrypt the data blob with the DEK.
  3. Include the salt, verification hash, wrapped DEKs, and Argon2id parameters.
  4. POST to /sync/push with an expected_version for conflict detection.
  5. On success, the server returns the new version number.
  1. GET from /sync/pull.
  2. The server returns the encrypted blob, salt, version, wrapped DEKs, and Argon2id parameters.
  3. Derive the MEK from the stored password + salt.
  4. Unwrap the DEK using the MEK.
  5. Decrypt the blob using the DEK.
  6. Restore data using additive merge (upsert, never delete).

Cloud Sync uses optimistic concurrency with version numbers:

  1. Each push includes an expected_version — the version the client last saw.
  2. If the server version matches, the push succeeds and the version increments.
  3. If the server version has advanced (another device pushed), the server responds with HTTP 409 and a SyncConflictException.
  4. The client must pull the latest data, merge with local changes, and retry the push.

The restore uses an additive merge (upsert) strategy:

  • Existing records are updated with the synced data.
  • New records are inserted.
  • Local records that are not in the sync blob are not deleted.

This prevents data loss when two devices have divergent data.

Because of DEK indirection, changing your sync password does not require re-encrypting all data:

  1. Derive a new MEK from the new password + new salt.
  2. Re-wrap the existing DEK with the new MEK.
  3. Push the updated wrapped DEK to the server.
  4. The encrypted data blob remains untouched.

If you forget your sync password:

  1. Enter your recovery key.
  2. ZestSSH derives the recovery KEK from the key + stored recovery salt.
  3. The server verifies the recovery hash.
  4. The DEK is unwrapped using the recovery KEK.
  5. Data is decrypted using the DEK.
  6. You can then set a new sync password (re-wraps the DEK with a new MEK).

To delete all sync data from the server:

  1. Go to sync settings and select Purge Data.
  2. Enter your sync password for verification.
  3. The verification hash is sent to /sync/purge.
  4. All encrypted data is permanently deleted from the server.

The verification hash requirement prevents data destruction by an attacker who only has the Firebase auth token.

Deleting your ZestSSH server account:

  1. Navigate to account settings.
  2. Select Delete Account.
  3. Enter your sync password for verification.
  4. The server deletes the account and all associated data via /account/delete.

Cloud Sync uses Firebase Authentication (Google Sign-In and Apple Sign-In). API calls include a Firebase ID token in the Authorization: Bearer header. The sync server verifies this token independently.