rypt docs
rypt is an HTTP API that encrypts and decrypts with keys it holds for you, in Google
Cloud. A Software (software) or Hardware (hsm) key is a Cloud KMS key of its own. A
Free (free) or Extra wrapped (wrapped) key is a set of data keys, one per key version,
stored wrapped under one shared Cloud KMS root key at the HSM protection level. Key
material stays inside rypt and Cloud KMS: no call returns it, and you cannot import your
own.
It offers two modes, five operations in all:
- Direct:
encryptanddecrypttake the data itself, 1 to 65,536 bytes of plaintext a call. On a Hardware key, plaintext and aad together may be at most 8,176 bytes. - Envelope:
wrapandunwraptake a data key, which you use to encrypt your data on your own machine.wrapcan generate the data key for you.
The fifth, rewrap, works in both modes: it moves a ciphertext or a wrapped data key to
the key's current version. Direct or envelope explains how
to choose.
There is no SDK. You call the HTTP API from your own code, or use rypt.sh from a shell.
What rypt sees
Section titled "What rypt sees"rypt is not zero-knowledge. In direct mode your plaintext travels to rypt in the request, and decrypt sends it back; on Software and Hardware keys it also goes to Cloud KMS, where the encryption runs. In envelope mode your data stays with you, but rypt sees every data key it wraps or unwraps for you, and on Software and Hardware keys so does Cloud KMS. rypt holds the keys that decrypt your data, and can use them.
The security model sets out what rypt sees, what it keeps and what it does not claim.
Base URL and requests
Section titled "Base URL and requests"The API is at https://api.rypt.dev. Every endpoint is under /v1, except that the
health check, /v1/healthz, is also served at /healthz.
Request and response bodies are JSON. Send Content-Type: application/json with every
request body: a body without a JSON content type is refused with
415 unsupported_media_type.
Binary fields (plaintext, ciphertext, aad, dek, wrapped) are standard base64,
the alphabet with + and /, with = padding, in requests and in responses. URL-safe
or unpadded base64 is refused with 400 invalid_base64. Sizes are counted after
decoding, but a request body over 128 KiB is refused whatever its fields hold: see
limits.
Every response carries an x-request-id header. A failed request answers with a JSON
body of error, message and request_id; errors lists every code.
Authentication
Section titled "Authentication"Send an API key as a bearer token:
Authorization: Bearer ry_K3pQ7xTa_...
An API key is 44 characters: ry_, an 8-character prefix, _, and a 32-character
secret, all letters and digits.
You issue API keys in the dashboard, on the API keys page. Only a dashboard session can issue, restrict or revoke one. The token is shown once, when it is issued, and cannot be recovered: if you lose it, revoke that API key and issue another. Storage says how rypt keeps it.
An API key works only with keys in its own container. A new API key has no actions
unless you choose some when you issue it. Actions do not restrict everything an API key
can do, and decrypt and unwrap overlap: read
what actions do not restrict
before you rely on them. Access control also covers key lists
and firewalls.
A missing, malformed, wrong or revoked API key gets 401 unauthorized, and the response
does not say which. A dashboard session cannot run the five operations: they answer it
with 403 api_key_required.
A key's tier is chosen when the key is created and cannot be changed.
| Tier | API id | Where encryption runs | Versions kept | Operations a month |
|---|---|---|---|---|
| Free | free |
In rypt, with AES-256-GCM, under a data key wrapped by the root key | 1 | 10,000, then refused |
| Extra wrapped | wrapped |
In rypt, the same way as Free | 1 | 50,000 included, then billed |
| Software | software |
In Cloud KMS, on a key at the SOFTWARE protection level | 3 | 100,000 included, then billed |
| Hardware | hsm |
In Cloud KMS, on a key at the HSM protection level | 2 | 250,000 included, then billed |
Prices are on rypt.dev.
Before you store anything:
- A Free key allows 10,000 operations a UTC calendar month. At that cap it refuses every
operation, decrypt included, with
429 ops_cap_reacheduntil the month ends. Paid keys are not capped: operations past the included number are billed. See the Free tier's monthly cap. - A paid key needs the tenant's billing in good standing to be created and to make new ciphertext. See billing refusals.
- A Free or Extra wrapped key keeps one version, so rotating it makes everything already
encrypted under it undecryptable at once, and
rewrapcannot prevent that. See rotation.
Quickstart
Section titled "Quickstart"This encrypts and decrypts hello world with a Free key, using curl and jq.
1. Create a key
Section titled "1. Create a key"- Sign in at dashboard.rypt.dev. Your first sign-in creates your tenant.
- Open Encryption keys and press Create key.
- Enter a Name, pick
freeunder Tier, and press Create key. - Open the key by its name in the list, and copy its Key id.
A tenant can hold one Free key, and a Free key pending deletion still holds that place.
If the free option is disabled, the tenant already has one, perhaps in another
container: use that key (restore it from its page first if it is pending deletion), and
issue the API key in its container. See
one Free key per tenant.
2. Issue an API key
Section titled "2. Issue an API key"- Open API keys and press Issue API key.
- Enter a Name. Under What it may do, in the Use keys group, tick
encryptanddecrypt. - Press Issue API key.
- Press Copy token and store the token. Tick I have stored this token. and press Done.
The key and the API key must be in the same container. Both pages act on the container chosen in the Container menu of the navigation. A new tenant has one, named Default.
Put both values in your shell:
export RYPT_TOKEN='ry_K3pQ7xTa_...' # the token
export KEY_ID='0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0' # your Key id
3. Encrypt
Section titled "3. Encrypt"aGVsbG8gd29ybGQ= is hello world in base64 (printf 'hello world' | base64).
curl -sS -X POST "https://api.rypt.dev/v1/keys/$KEY_ID/encrypt" \
-H "Authorization: Bearer $RYPT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"plaintext": "aGVsbG8gd29ybGQ="}' | tee encrypted.json
The response has one field:
{"ciphertext":"...base64..."}
Store the ciphertext: rypt keeps no copy of it. It names the key version it was made
under, so decrypt needs only it and the key, plus the same aad if you sent one.
4. Decrypt
Section titled "4. Decrypt"CIPHERTEXT=$(jq -r .ciphertext encrypted.json)
curl -sS -X POST "https://api.rypt.dev/v1/keys/$KEY_ID/decrypt" \
-H "Authorization: Bearer $RYPT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"ciphertext\": \"$CIPHERTEXT\"}"
{"plaintext":"aGVsbG8gd29ybGQ="}
To print the text, pipe that response through jq -r .plaintext | base64 --decode,
which prints hello world. Each call was one operation of the key's monthly 10,000.
If it fails
Section titled "If it fails"| Response | Cause |
|---|---|
401 unauthorized |
RYPT_TOKEN is not the full token, or the API key was revoked. |
403 action_not_allowed |
The API key was not given that action. Add it with Restrict on the API keys page. |
403 api_key_required |
The bearer token is a dashboard session, not an API key. |
404 not_found |
KEY_ID is wrong, or the key is in another container than the API key. |
409 key_pending_deletion |
The key was deleted. Press Restore on its page. |
Command line
Section titled "Command line"rypt.sh is a POSIX shell script that encrypts and decrypts files,
or standard input, with encrypt and decrypt. That is direct mode: the file's contents
go to rypt, and a file can be at most 65,536 bytes, or 8,176 bytes together with its
--aad on a Hardware key. It needs curl and base64, and uses jq when it is installed.
curl -fsSL https://sh.rypt.dev/install | sh
The installer puts the script in ~/.local/bin/rypt and, at a terminal, asks for an API
key with the input hidden and saves it in ~/.config/rypt/api-key, readable only by you. The script reads
the API key from that file, or from RYPT_API_KEY (not RYPT_TOKEN). Give the API key
the encrypt and decrypt actions.
rypt keys # the id, tier and name of each key
rypt encrypt --key "$KEY_ID" notes.txt # writes notes.txt.enc
rypt decrypt --key "$KEY_ID" -o - notes.txt.enc # prints the plaintext
--key takes a key's name or its id. A .enc file holds the ciphertext exactly as the
API returned it, as one line of base64. Without -o, decrypt writes notes.txt, and
neither command replaces an existing file unless you pass --force.
Where next
Section titled "Where next"- Direct or envelope: which mode to use, and what reaches rypt in each.
- Access control: containers, firewalls, key lists, and what an API key may do.
- Additional authenticated data: binding a
ciphertext to its context with
aad. - Limits: payload sizes, the Free tier's cap, and the rate limit.
- Rotation: what a rotation does to existing ciphertext on each tier.
- Audit log: what rypt records for each key, and how to read it.
- Security model: what rypt sees and stores, and what it does not claim.
- Errors: the error body and every code.
- API reference: every endpoint, request and response.
- OpenAPI document: the machine-readable description, as YAML or JSON.