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).
Zero-Knowledge Architecture
Section titled “Zero-Knowledge Architecture”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.
What Syncs
Section titled “What Syncs”| Data | Synced | Notes |
|---|---|---|
| Connections | Yes | Host, port, label, group, protocol, keep-alive, startup command, WoL settings, environment variables, agent forwarding, sort order |
| Identities | Yes | Username, auth method, key type, public key fingerprint/data, default flag |
| Identity secrets | Yes | Passwords and private keys (encrypted in the sync blob, also written to secure storage on restore) |
| Connection groups | Yes | Name, sort order, expanded state |
| Known hosts | Yes | Host, port, key type, fingerprint, public key, first/last seen timestamps |
| Snippets | Yes | Label, command, category, confirm-before-run flag, default flag, sort order |
| Port forward rules | Yes | Connection ID, type, bind address/port, remote host/port, auto-start flag, label |
Schema Version
Section titled “Schema Version”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.
What Doesn’t Sync
Section titled “What Doesn’t Sync”| Data | Reason |
|---|---|
| Terminal transcripts / session recordings | Too large; device-specific |
| Automation history / audit logs | Device-specific execution records |
| App settings and preferences | Theme choices, font sizes, UI preferences are personal to each device |
| Terminal theme customizations | Stored locally in SharedPreferences |
| Auto-backup passwords | Device-specific secure storage |
Sync Flow
Section titled “Sync Flow”Initial Setup
Section titled “Initial Setup”- Sign in with Google or Apple (Firebase Auth).
- ZestSSH verifies Cloud Sync entitlement with the server.
- Choose a sync password (minimum length enforced).
- A random DEK is generated.
- The MEK is derived from the password + random salt.
- A recovery key is generated and displayed (save it securely).
- The DEK is wrapped with both the MEK and recovery KEK.
- All local data is encrypted and pushed.
Push (Upload)
Section titled “Push (Upload)”- Gather all data from the 6 DAOs + secure storage secrets.
- Encrypt the data blob with the DEK.
- Include the salt, verification hash, wrapped DEKs, and Argon2id parameters.
- POST to
/sync/pushwith anexpected_versionfor conflict detection. - On success, the server returns the new version number.
Pull (Download)
Section titled “Pull (Download)”- GET from
/sync/pull. - The server returns the encrypted blob, salt, version, wrapped DEKs, and Argon2id parameters.
- Derive the MEK from the stored password + salt.
- Unwrap the DEK using the MEK.
- Decrypt the blob using the DEK.
- Restore data using additive merge (upsert, never delete).
Conflict Resolution
Section titled “Conflict Resolution”Cloud Sync uses optimistic concurrency with version numbers:
- Each push includes an
expected_version— the version the client last saw. - If the server version matches, the push succeeds and the version increments.
- If the server version has advanced (another device pushed), the server responds with HTTP
409and aSyncConflictException. - The client must pull the latest data, merge with local changes, and retry the push.
Merge Strategy
Section titled “Merge Strategy”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.
Password Change
Section titled “Password Change”Because of DEK indirection, changing your sync password does not require re-encrypting all data:
- Derive a new MEK from the new password + new salt.
- Re-wrap the existing DEK with the new MEK.
- Push the updated wrapped DEK to the server.
- The encrypted data blob remains untouched.
Recovery
Section titled “Recovery”If you forget your sync password:
- Enter your recovery key.
- ZestSSH derives the recovery KEK from the key + stored recovery salt.
- The server verifies the recovery hash.
- The DEK is unwrapped using the recovery KEK.
- Data is decrypted using the DEK.
- You can then set a new sync password (re-wraps the DEK with a new MEK).
Data Purge
Section titled “Data Purge”To delete all sync data from the server:
- Go to sync settings and select Purge Data.
- Enter your sync password for verification.
- The verification hash is sent to
/sync/purge. - 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.
Account Deletion
Section titled “Account Deletion”Deleting your ZestSSH server account:
- Navigate to account settings.
- Select Delete Account.
- Enter your sync password for verification.
- The server deletes the account and all associated data via
/account/delete.
Authentication
Section titled “Authentication”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.