Skip to content

Encryption

Clonit Agent uses AES-GCM encryption to protect sensitive data at rest in the SQLite database. Any field that could contain credentials or secrets is encrypted before being written to disk and decrypted when read back.

The following fields are encrypted at rest:

  • Database connection URLs – these typically contain usernames and passwords (e.g., postgresql://user:password@host:5432/dbname)
  • Storage profile access keys – used to authenticate with cloud storage providers
  • Storage profile secret keys – the secret component of cloud storage credentials

All encrypted data is prefixed with $aes$ so the system can detect whether a value is already encrypted. This enables idempotent encryption: attempting to encrypt an already-encrypted value is a no-op, and the system can reliably distinguish between plaintext and ciphertext when reading data.

The secret key is the foundation of all encryption in Clonit Agent.

  • Generated automatically during config init (16 random bytes, hex-encoded to produce a 32-character string)
  • Stored in ~/.config/clonit/config.yaml as secret_key
  • Used as the AES-128 encryption key for all sensitive fields
  • Unrecoverable if lost – there is no key escrow or recovery mechanism

Clonit Agent uses AES-GCM (Galois/Counter Mode), which provides authenticated encryption. This means the ciphertext is both confidential and tamper-proof.

The encryption process:

  1. A random 12-byte nonce is generated for each encryption operation, ensuring that encrypting the same plaintext twice produces different ciphertext
  2. The plaintext is encrypted using AES-GCM with the secret key and nonce
  3. The resulting ciphertext includes both the encrypted data and an authentication tag that detects any tampering
  4. The final stored value has the format: $aes$<hex-encoded nonce + ciphertext>

The decryption process:

  1. The $aes$ prefix is stripped
  2. The hex-encoded payload is decoded
  3. The nonce is extracted from the first 12 bytes
  4. AES-GCM decrypts and verifies the authentication tag
  5. The original plaintext is returned

Encryption and decryption are handled transparently by the model repositories so that callers never need to manage encryption directly.

  • When writing: sensitive fields are encrypted before being stored in SQLite. If a field is already encrypted (detected by the $aes$ prefix), it is left as-is.
  • When reading: fields with the $aes$ prefix are decrypted automatically before being returned to the caller.
  • CLI display: database URLs are shown with passwords masked (replaced with ****) rather than displaying the full decrypted credentials. This prevents accidental exposure of secrets in terminal output or logs.

This design keeps encryption concerns out of the service and command layers entirely. The repository layer is the single point of responsibility for protecting sensitive data.