Revaulter GitHub

Using the Revaulter CLI

The Revaulter CLI (revaulter-cli) is the primary way to submit encrypt, decrypt, and sign requests.

Using the CLI is strongly recommended over calling the REST API directly: it handles transport key generation, end-to-end encryption, long-polling, and result decryption automatically.

Installing the CLI#

Download the latest release from GitHub Releases . Binaries are available for Linux (amd64, arm64), macOS (amd64, arm64), and Windows.

Docker#

docker run --rm ghcr.io/italypaleale/revaulter-cli:2 <command> [flags]

For example:

docker run --rm ghcr.io/italypaleale/revaulter-cli:2 encrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label my-key \
  --algorithm A256GCM \
  --value SGVsbG8

Commands#

encrypt#

Submit an encryption request for approval.

revaulter-cli encrypt [flags]
FlagShortRequiredDescription
--server-sYesAddress of the Revaulter server (e.g. https://revaulter.example.com)
--request-key-kYesPer-user request key (shown in the web UI after registration)
--key-label-lYesLogical key label used for key derivation
--algorithm-aYesAEAD algorithm identifier: A256GCM (alias aes-256-gcm) or C20P (alias chacha20-poly1305)
--message-mOne of --message, --input, or --json is requiredThe message to encrypt as a raw UTF-8 string.
--input-iOne of --message, --input, or --json is requiredPath to a file whose bytes will be encrypted; use - to read from stdin
--jsonOne of --message, --input, or --json is requiredPath to a JSON file (or - to read from stdin) of shape {"value":"<base64url>","additionalData":"<base64url>"} (additionaldata is optional)
--aadNoAdditional authenticated data (base64-encoded). Not allowed with --json
--timeout-tNoTimeout for the operation (number of seconds or Go duration, e.g. 5m, 300)
--note-nNoMessage displayed alongside the request (up to 40 chars, alphanumeric and . / _ - only)
--output-oNoWrite the result to a file instead of stdout
--formatNoOutput format: json (only). Encrypt always emits the JSON envelope on stdout
--insecureNoSkip TLS certificate validation
--no-h2cNoDo not attempt HTTP/2 Cleartext when not using TLS
--verbose-VNoShow debug-level logs

Example (raw string):

revaulter-cli encrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label boot-disk \
  --algorithm A256GCM \
  --message "Hello, world" \
  --note "boot unlock"

Example (read plaintext from a file):

revaulter-cli encrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label boot-disk \
  --algorithm A256GCM \
  --input ./secret.bin

Example (JSON input):

echo '{"value":"SGVsbG8"}' | revaulter-cli encrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label boot-disk \
  --algorithm A256GCM \
  --json -

decrypt#

Submit a decryption request for approval.

revaulter-cli decrypt [flags]
FlagShortRequiredDescription
--server-sYesAddress of the Revaulter server (e.g. https://revaulter.example.com)
--request-key-kYesPer-user request key (shown in the web UI after registration)
--key-label-lYesLogical key label used for key derivation
--algorithm-aYesAEAD algorithm identifier: A256GCM (alias aes-256-gcm) or C20P (alias chacha20-poly1305). Must match what was used at encryption time
--value-mOne of --value or --json is requiredThe ciphertext to decrypt, base64-encoded
--tag-gRequired when not using --jsonAuthentication tag, base64-encoded
--nonceRequired when not using --jsonNonce/IV, base64-encoded
--aadNoAdditional authenticated data, base64-encoded (only allowed not using --json)
--json-jOne of --value or --json is requiredPath to a JSON file (or - to read from stdin) in the shape produced by encrypt ({"value":"<base64url>","nonce":"<base64url>","tag":"<base64url>","additionalData":"<base64url>"}). Mutually exclusive with --value, --tag, --nonce, and --aad
--timeout-tNoTimeout for the operation (number of seconds or Go duration, e.g. 5m, 300)
--note-nNoMessage displayed alongside the request (up to 40 chars, alphanumeric and . / _ - only)
--output-oNoWrite the result to a file instead of stdout
--formatNoOutput format: json (default — JSON envelope) or raw (write the decrypted plaintext as raw bytes)
--insecureNoSkip TLS certificate validation
--no-h2cNoDo not attempt HTTP/2 Cleartext when not using TLS
--verbose-VNoShow debug-level logs

Example:

revaulter-cli decrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label boot-disk \
  --algorithm A256GCM \
  --value <base64-ciphertext> \
  --nonce <base64-nonce> \
  --tag <base64-tag>

Example (JSON input — pipes encrypt’s output back in):

revaulter-cli encrypt --message "secret" ... \
  | revaulter-cli decrypt \
    --server https://revaulter.example.com \
    --request-key AbCdEf0123456789GhIj \
    --key-label boot-disk \
    --algorithm A256GCM \
    --json - \
    --format raw

Write result to a file (“raw” format):

revaulter-cli decrypt \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label boot-disk \
  --algorithm A256GCM \
  --value <base64-ciphertext> \
  --nonce <base64-nonce> \
  --tag <base64-tag> \
  --output /tmp/decrypted.bin \
  --format raw

sign#

Submit a signing request for approval. The CLI always pre-hashes the message with SHA-256 client-side, so only the 32-byte digest is sent to the server — the raw message is never transmitted.

revaulter-cli sign [flags]
FlagShortRequiredDescription
--server-sYesAddress of the Revaulter server
--request-key-kYesPer-user request key
--key-label-lYesLogical key label used for signing-key derivation
--algorithm-aYesSigning algorithm identifier (currently ES256)
--input-iOne of --input or --digest is requiredPath to the message file to sign; use - for stdin. The CLI hashes the file contents with SHA-256
--digest-dOne of --input or --digest is requiredA pre-computed 32-byte SHA-256 digest, encoded as hex or base64url. Mutually exclusive with --format jws
--formatNoOutput format: json (default — JSON envelope with base64url r || s signature), jws (compact JWS string), or raw (the 64-byte r || s signature). jws requires --input
--jws-headerNoJSON fragment merged into the default protected header when building a JWS from --input. The alg field is always forced to ES256; other fields like kid or typ can be supplied
--timeout-tNoTimeout for the operation
--note-nNoMessage displayed alongside the request
--output-oNoWrite the result to a file instead of stdout
--insecureNoSkip TLS certificate validation
--no-h2cNoDo not attempt HTTP/2 Cleartext when not using TLS
--verbose-VNoShow debug-level logs

Examples:

Sign a file (default output is a JSON envelope containing the base64url r || s signature):

revaulter-cli sign \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label release-signing \
  --algorithm ES256 \
  --input manifest.json

Sign data piped from stdin:

echo "hello" | revaulter-cli sign \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label release-signing \
  --algorithm ES256 \
  --input -

Sign a pre-computed SHA-256 digest (useful when integrating with other tooling that already hashes):

revaulter-cli sign \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label release-signing \
  --algorithm ES256 \
  --digest d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

Emit a compact JWS over a file, merging a custom kid into the protected header:

revaulter-cli sign \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label release-signing \
  --algorithm ES256 \
  --input manifest.json \
  --format jws \
  --jws-header '{"kid":"release-signing-2026"}'

Write just the raw 64-byte r || s signature to a file (useful for pipelines that verify with a separate tool):

revaulter-cli sign \
  --server https://revaulter.example.com \
  --request-key AbCdEf0123456789GhIj \
  --key-label release-signing \
  --algorithm ES256 \
  --input manifest.json \
  --format raw \
  --output manifest.sig

Note: ECDSA signatures are non-deterministic by design (a fresh random k per signature, per FIPS 186-5). Signing the same input twice produces two different but equally valid signatures — this is expected.


check#

Verify that a Revaulter server is serving unmodified web client assets, signed by this repo’s release workflow. See Verifying the web client’s integrity for a deeper explanation of the trust model and when to run this.

revaulter-cli check --server https://revaulter.example.com
FlagShortRequiredDescription
--server-sYesAddress of the Revaulter server
--timeout-tNoOverall timeout for the check (e.g. 60s, 2m); defaults to 60s
--insecureNoSkip TLS certificate validation
--no-h2cNoDo not attempt HTTP/2 Cleartext when not using TLS
--verbose-VNoShow debug-level logs

version#

Print the CLI version.

revaulter-cli version

How it works#

When you run revaulter-cli encrypt, decrypt, or sign, the CLI:

  1. Fetches the user’s public encryption keys from the server
  2. Generates an ephemeral ECDH P-256 keypair and an ML-KEM-768 encapsulation
  3. Encrypts the request payload end-to-end to the user’s public keys
  4. Submits the encrypted request to the server
  5. Long-polls for the result
  6. Decrypts the response envelope locally using its ephemeral private key

For sign specifically, the CLI pre-hashes the input with SHA-256 before encrypting, so only the 32-byte digest is ever transmitted end-to-end. The server and the browser never see the raw message.

The server never has access to the plaintext request or response data.

Output#

By default, the CLI writes a JSON envelope (--format json) to stdout after decrypting the response:

{
  "value": "<base64>"
}
  • For decrypt: --format raw writes the decrypted plaintext as raw bytes — useful for piping into other commands or writing binary data to a file with --output.
  • For sign: --format also accepts jws (compact JWS) and raw (the 64-byte r || s signature).

Exit codes#

  • 0 — the operation completed successfully
  • non-zero — the request was denied, canceled, expired, or an error occurred (details are printed to stderr)
Edit this page on GitHub