---
title: "Encryption"
description: "OpenPGP to a key you supply, applied on your machine for local backups."
url: "https://saved.sh/docs/security/encryption"
---

Artifacts are encrypted with **OpenPGP** (RFC 4880) to a public key you provide. We never
hold the private half.

There is no proprietary scheme here, and that is the point: the artifact is readable by any
OpenPGP implementation, on any platform, with no software of ours.

## Where it happens [#where-it-happens]

**This is the difference that matters**, and it follows from the backup's kind.

| Kind     | Encrypted by                   | Plaintext exists on | We could read it                |
| -------- | ------------------------------ | ------------------- | ------------------------------- |
| `local`  | **Your worker**, before upload | Your host only      | **No**                          |
| `cloud`  | Us, after we take the dump     | Our infrastructure  | During the run, yes             |
| `manual` | Us, after your upload          | Our infrastructure  | Between upload and encrypt, yes |

For a local backup, ciphertext is all we ever receive. For the other two we necessarily
handle plaintext, because we produced it or you sent it to us. Encryption there protects the
**archive at rest**, not the pipeline that made it.

<Callout>
  If "they cannot read it even in principle" is the requirement, that is a local backup, or a
  manual backup you encrypted yourself before uploading. A cloud backup cannot offer it, and
  we would rather say so than blur the two.
</Callout>

## The scheme [#the-scheme]

| Property       | Value                                                          |
| -------------- | -------------------------------------------------------------- |
| Standard       | OpenPGP, RFC 4880                                              |
| Key type       | Whatever your public key is. RSA and ECC both work             |
| Session key    | Generated per message by the OpenPGP implementation            |
| Compression    | zlib, **inside** the PGP message, when compression is enabled  |
| Integrity      | SHA-256 over the uploaded bytes, recorded on the artifact      |
| Implementation | A maintained Go OpenPGP library, on the worker and on our side |

The artifact is a single OpenPGP message. `gpg --decrypt` opens it, and so does anything
else that speaks the standard.

## What it defends, and what it does not [#what-it-defends-and-what-it-does-not]

| Defends against                               | Does not defend against                             |
| --------------------------------------------- | --------------------------------------------------- |
| Us reading your local backups                 | Anyone holding your private key                     |
| Our storage provider reading them             | Someone with root on your worker, before encryption |
| A leaked archive credential exposing contents | An artifact already downloaded and decrypted        |
| A stolen backup file being readable           | A cloud backup's plaintext during the run           |

Encryption is a confidentiality control. It does nothing about deletion, which is
[retention and locking](/docs/backups/retention), and nothing about access, which is
[permissions](/docs/security/permissions).

## What happens without a key [#what-happens-without-a-key]

Encryption is **optional**.

<Callout type="error">
  A backup with no public key configured produces **plaintext artifacts**, and nothing refuses
  to run, warns at run time, or flags it afterwards. The worker simply skips the encrypt step
  and uploads what came out of the dump.
</Callout>

There is no server-side encryption standing behind that as a fallback, and we do not offer
one as a substitute. Server-side encryption protects against a stolen disk and nothing else,
because whoever can read the bucket reads through it. Claiming it as a security feature would
be misleading, so it is not claimed.

Check what you actually have:

```bash
sctl artifact get <artifact-id>
```

`Encrypted: no` on an artifact you assumed was encrypted is the single most valuable output
of a [rehearsal](/docs/recover/rehearsal).

## Key identity [#key-identity]

Each artifact records the **fingerprint** of the public key it was encrypted to, so you never
have to guess which key opens which file. The artifact itself carries it too, independently
of us:

```bash
gpg --list-packets artifact | head -3
```

```
:pubkey enc packet: version 3, algo 1, keyid 3AA5C34371567BD2
```

This is what makes key rotation survivable: after a rotation, artifacts of the same backup
need different keys, and each one says which.

## Transport [#transport]

Everything is TLS in addition to the above.

| Hop                             | Protection                           |
| ------------------------------- | ------------------------------------ |
| Worker to our API               | TLS                                  |
| Worker to the orchestration hub | TLS, on by default                   |
| Worker to object storage        | TLS, presigned URL scoped to one run |
| Browser and CLI to our API      | TLS                                  |

Transport encryption is table stakes and is not the interesting control here. The interesting
control is that the payload is already ciphertext before it enters any of those hops on the
local path.

## Verifying it for yourself [#verifying-it-for-yourself]

The claim "encrypted before it leaves your network" is checkable without trusting this page.

**Watch the bytes.** The worker stages the dump and then the encrypted copy as separate
files under `local_temp_path`. The second one starts with an OpenPGP packet header, and the
uploaded object is that file.

**Read the code.** The worker is open source, and it is the one component that runs on your
machine holding your credentials. The encrypt step is a few dozen lines.

**Try to read an artifact without the key.** Download one, and run `gpg --decrypt` on a
machine that does not have the private key. It fails, and it fails for us in exactly the same
way.

## Next [#next]

<Cards>
  <Card href="/docs/security/key-management" title="Key management" description="Generating, storing and rotating the key this all rests on." />

  <Card href="/docs/recover/artifact-format" title="Artifact format" description="Opening one with plain gpg." />

  <Card href="/docs/backups/encryption" title="Configuring encryption" description="Where to put the key, per kind." />
</Cards>
