Skip to content

Encrypted Backups

ZestSSH backup files use the .zest format. All backups are encrypted — there is no option to export an unencrypted dump. Storing plaintext SSH credentials, private keys, and known hosts in user-accessible storage would be a serious security risk if the device is shared, lost, or scanned by another app.

This is a free feature — not paywalled.

Every .zest file has the following binary structure:

OffsetSizeContent
04 bytesMagic bytes: ZEST (ASCII)
41 byteVersion byte
5VariableEncrypted payload
VersionMeaning
1Encrypted (current) — AES-256-GCM with Argon2id-derived key
2Legacy unencrypted JSON (import-only, never generated by current builds)

The encrypted payload is structured as:

salt(32 bytes) + IV(12 bytes) + GCM tag(16 bytes) + ciphertext
  • Salt: 32 random bytes used for Argon2id key derivation.
  • IV: 12-byte AES-GCM initialization vector.
  • GCM tag: 16-byte authentication tag for integrity verification.
  • Ciphertext: zlib-compressed JSON, encrypted with AES-256-GCM.
  1. All app data is gathered via SyncDataService.gatherAll() into a JSON map.
  2. A 32-byte random salt is generated.
  3. The user’s backup password is run through Argon2id with the salt to derive a 256-bit key (same parameters as Cloud Sync: 64 MB memory, 3 iterations, 4 parallelism).
  4. The JSON is zlib-compressed and encrypted with AES-256-GCM using the derived key.
  5. The output is prefixed with the ZEST magic bytes and version 1.
  • Minimum length: 12 characters
  • Empty or short passwords are rejected before any encryption occurs.
  • The 12-character minimum is enforced because backups land in user-accessible storage (Downloads folder, Files app), where the password is the only barrier against an offline attacker.

A backup contains everything needed to fully restore your ZestSSH configuration:

DataIncluded
Connections (host, port, settings, groups)Yes
Identities (usernames, auth methods)Yes
Identity secrets (passwords, private keys)Yes (encrypted)
Connection groupsYes
Known hosts (fingerprints)Yes
SnippetsYes
Port forward rulesYes

Data that is not included:

  • Terminal transcripts / session recordings
  • Automation history / audit logs
  • App settings and preferences
  • Theme customizations
  1. Go to Settings > Backup & Restore > Export Backup.
  2. Enter a backup password (minimum 12 characters).
  3. ZestSSH encrypts all data and writes the .zest file.
PlatformLocation
Android/storage/emulated/0/Download/
iOSApplication Documents (accessible via the Files app)
Desktop (Windows/macOS/Linux)Documents/ZestSSH/backups/
  • Manual backups: zestssh_backup_YYYY-MM-DDTHH-MM-SS.zest
  • Auto-backups: zestssh_auto_YYYY-MM-DDTHH-MM-SS.zest
  1. Go to Settings > Backup & Restore > Import Backup.
  2. Select a .zest file.
  3. Enter the backup password.
  4. ZestSSH decrypts and restores the data.
  • Additive merge: Local data is NOT deleted. Existing records are updated, new records are inserted. This is an upsert, not a replace.
  • Identity secrets are restored to Flutter Secure Storage after the database transaction succeeds, preventing orphaned secrets if the transaction rolls back.
  • Legacy v2 backups (unencrypted) are accepted for backward compatibility but trigger a UI warning urging the user to re-export with a password.

Files larger than 50 MB are rejected before loading into memory to prevent out-of-memory crashes from malicious or corrupted files.

ErrorCause
”Invalid backup file format”Missing or incorrect ZEST magic bytes
”This backup is password-protected”Version 1 file but no password entered
”Wrong password or corrupted backup”AES-GCM decryption failed (wrong key or tampered data)
“Unsupported backup version”Unknown version byte
”Backup file is too large (max 50 MB)“File exceeds the safety limit
”Backup file not found”File path does not exist