File Formats
ZestSSH uses and supports several file formats for backups, themes, and key management.
.zest (Encrypted Backup)
Section titled “.zest (Encrypted Backup)”Extension: .zest
Purpose: Full encrypted backup of all ZestSSH data.
Created by: Settings > Backup > Export Backup
Structure
Section titled “Structure”Offset Length Content0 4 Magic bytes: "ZEST" (ASCII)4 1 Version byte5+ var PayloadVersion 3 (Current --- Encrypted)
Section titled “Version 3 (Current --- Encrypted)”The payload is an encrypted blob containing all connections, identities, connection groups, known hosts (stored in the file but never applied on restore, see below), snippets, and port forward rules serialized as JSON.
Payload layout: header_length(2) + argon2_params_header(JSON) + salt(32) + IV(12) + gcm_tag(16) + ciphertext. The header records the Argon2 parameters the backup was written under, so it still decrypts correctly after the app’s default parameters change.
Encryption: AES-256-GCM with a key derived from the user’s backup password via Argon2id.
Key Derivation:
- Algorithm: Argon2id
- Salt: 32 random bytes (inside the payload, after the Argon2-parameters header)
- The derived 256-bit key encrypts the JSON data with AES-256-GCM
- A 16-byte authentication tag ensures integrity
Password Requirements:
- Minimum 12 characters
- Empty or short passwords are rejected --- there is no plaintext backup path
Import Behavior: Upsert plus tombstones: imports use the same restore path as sync. Existing records (matched by ID) are updated, new records are added, and the imported blob’s deletion tombstones remove local records whose deletion they carry. A timestamped record survives an imported tombstone only if it is newer than the tombstone’s deletedAt; timestamp-less configuration records are delete-wins. Importing an older backup can therefore roll back or delete newer local data, not only add to it.
Known hosts: included in the payload as ciphertext, but a restore intentionally never applies them; each device re-learns host keys through its own Trust-On-First-Use.
Version 1 (Legacy --- Encrypted)
Section titled “Version 1 (Legacy --- Encrypted)”Older builds produced encrypted backups with version byte 1 and no Argon2-parameters header: salt(32) + IV(12) + gcm_tag(16) + ciphertext. The importer still accepts these: it derives with the app’s current default Argon2id parameters and falls back to the older parameters if that fails.
Version 2 (Legacy --- Unencrypted)
Section titled “Version 2 (Legacy --- Unencrypted)”Older builds produced unencrypted backups with version byte 2. These contain the JSON data directly after the header with no encryption.
ZestSSH can still import version 2 backups for backward compatibility, but refuses the import unless the user explicitly confirms an unprotected import. Version 2 backups are never created by current builds.
File Size Limit
Section titled “File Size Limit”On import, ZestSSH rejects backup files larger than 50 MB to prevent memory exhaustion from malicious files.
Storage Location
Section titled “Storage Location”- Android:
/storage/emulated/0/Download/ - iOS: App Documents directory (accessible via Files app)
- Desktop:
Documents/ZestSSH/backups/
Auto-backups use the prefix zestssh_auto_ while manual backups use zestssh_backup_.
.zestheme (Custom Theme)
Section titled “.zestheme (Custom Theme)”Extension: .zestheme
Purpose: Custom terminal color scheme.
Format: JSON with three top-level keys: name (string), type (string), and colors (object containing 20 keys).
A .zestheme file defines the 16 ANSI colors plus foreground, background, cursor, and selection colors for the terminal emulator. The colors object contains exactly 20 keys: background, foreground, cursor, selection, and the 16 ANSI colors (black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite).
PuTTY .ppk (Import Only)
Section titled “PuTTY .ppk (Import Only)”Extension: .ppk
Purpose: PuTTY private key format. ZestSSH imports .ppk files and converts them to OpenSSH PEM format internally.
Supported Versions
Section titled “Supported Versions”- PPK v2: Uses SHA-1 based key derivation for encrypted keys.
- PPK v3: Uses Argon2id key derivation for encrypted keys.
Supported Key Types in PPK
Section titled “Supported Key Types in PPK”- RSA
- Ed25519
Only ssh-rsa and ssh-ed25519 PPK keys are supported. PPK files containing ECDSA or DSA keys are rejected with an “unsupported key type” error.
Import Process
Section titled “Import Process”- ZestSSH reads the
.ppkfile structure. - If encrypted, prompts for the passphrase.
- Extracts the key material.
- Converts to OpenSSH PEM format.
- Stores the PEM key in the platform’s secure keychain.
The original .ppk file is not modified or retained.
OpenSSH Key Formats (Import)
Section titled “OpenSSH Key Formats (Import)”ZestSSH imports standard OpenSSH private keys in these formats:
Modern OpenSSH Format
Section titled “Modern OpenSSH Format”-----BEGIN OPENSSH PRIVATE KEY-----base64-encoded data-----END OPENSSH PRIVATE KEY-----This is the default format for keys generated by ssh-keygen on OpenSSH 7.8+. Supports all key types (Ed25519, RSA, ECDSA). Encrypted keys use AES-256-CTR with bcrypt KDF.
Legacy PEM Format (RSA)
Section titled “Legacy PEM Format (RSA)”-----BEGIN RSA PRIVATE KEY-----base64-encoded data-----END RSA PRIVATE KEY-----The older format for RSA keys. May include Proc-Type: 4,ENCRYPTED and DEK-Info headers for passphrase-protected keys.
PKCS#8 Format
Section titled “PKCS#8 Format”-----BEGIN PRIVATE KEY-----base64-encoded data-----END PRIVATE KEY-----Or encrypted:
-----BEGIN ENCRYPTED PRIVATE KEY-----base64-encoded data-----END ENCRYPTED PRIVATE KEY-----PKCS#8 is a generic private key container that ZestSSH can read for RSA, ECDSA, and Ed25519 keys.
SSH Config (Import)
Section titled “SSH Config (Import)”File: ~/.ssh/config (or any text file in SSH config format)
Purpose: Bulk import of connection definitions.
ZestSSH parses the following directives:
| Directive | Mapped To |
|---|---|
Host | Connection label |
HostName | Connection host |
Port | Connection port |
User | Identity username |
IdentityFile | Noted but not auto-imported (import keys separately) |
ProxyJump | Connect Via (if the referenced host is also imported) |
Wildcard hosts (Host *) are skipped. Invalid hostnames, ports outside 1-65535, usernames with control characters, and identity file paths with .. traversal are rejected with warnings.
Limitations
Section titled “Limitations”Matchblocks are not supported.Includedirectives are not followed.LocalForwardandRemoteForwarddirectives are not parsed.- The actual key files referenced by
IdentityFileare not imported automatically --- you must import them as identities separately.