Skip to content

Encrypt and decrypt data

Protect data with a key of your tenant and recover it later, as a JWE (RFC 7516), either in one request or streamed for large files.

Who can do it

An application authenticated as a cryptographic actor of your tenant. Its token must carry the scope of the operation, and the actor must hold an active Capability Grant for the operation on the key:

Operation Scope Capability Grant
Encrypt in one request secure.encrypt ENCRYPT on the key
Decrypt in one request secure.decrypt DECRYPT on the key
Encrypt a stream stream.encryptStream ENCRYPT on the key
Decrypt a stream stream.decryptStream DECRYPT on the key

No console role performs these operations.

Before you start

  • An encryption key exists in the tenant, with a key identifier your application knows. See Create a key.
  • The application can obtain a token. See Get an access token for an application.
  • For large files, the streaming operations need HTTP/2 over https. The SDK refuses to stream over HTTP/1.1 or plain http before sending anything.

Steps

  1. Encrypt:
    • Java SDK: sdk.encrypt(kid, plaintext) returns an EncryptResult; keep getJweToken(). For files, sdk.encryptFile(kid, input, output) chooses the one-request or the streaming operation from the server's size limit.
    • Crypto CLI: AnkaSecureCLI encrypt-file --kid <kid> --input-file <file> --output-file <file>. Large files stream automatically; encrypt-file-stream always streams.
    • API: POST /api/v3/crypto/encrypt with {"kid": "<kid>", "data": "<base64 plaintext>"}. For a stream, POST /api/v3/crypto/stream/encrypt with a multipart/form-data body whose metadata part comes before the file part.
  2. Store the JWE exactly as it was returned. A JWE made with an asymmetric or composite key carries a key confirmation member, ank_kc; the platform refuses a JWE without it, or one whose recipient key identifier, version, algorithm or tenant was edited.
  3. Decrypt:
    • Java SDK: sdk.decrypt(jwe) returns a DecryptResult; read getDecryptedData(). For files, sdk.decryptFile(input, output) picks the path from the input's format.
    • Crypto CLI: AnkaSecureCLI decrypt-file --input-file <file> --output-file <file>, or decrypt-file-stream for a streaming artifact.
    • API: POST /api/v3/crypto/decrypt with {"jweToken": {...}}. For a stream, POST /api/v3/crypto/stream/decrypt with the multipart/mixed header and ciphertext parts.
  4. If the JWE is addressed to several keys, name the one your actor decrypts with: recipientKid in the request body, the recipientKid query parameter for a stream, sdk.decrypt(recipientKid, jwe) or --recipient-kid in the CLI. Only that recipient is tried.
  5. On a streaming decrypt, wait for the verdict. The plaintext arrives in the first response part, before the end-of-stream integrity check; the trailing verdict part says whether it holds. Treat the output as untrusted until the verdict is VALID. The SDK and the CLI do this for you: they write to <output>.part and rename it only on a VALID verdict.

What you see when it worked

An encryption returns the JWE in General JSON serialization (jweToken), with keyRequested, materialVersion, algorithmUsed and any warnings, such as a key nearing its usage limit or its sunset. A composite key's JWE carries one recipient per component.

A decryption returns the plaintext with the key and material version that were used. A streaming decryption ends with a verdict part whose verdict is VALID; through the SDK or the CLI, the output file exists only then.

If it fails

What you see Cause What to do
403 .../errors/forbidden The token lacks the scope, the actor holds no active Capability Grant for the operation on the key, a grant constraint is violated, its exchange context is suspended, or the tenant or actor is not in a state that permits cryptographic operations Ask a tenant administrator to check the actor's roles and grants
404 .../errors/not-found The key does not exist in the tenant, or lacks the part the operation needs Check the key identifier
409 .../errors/conflict The key is suspended or revoked Use an active key; durable, do not retry
409 .../errors/key-protection-backend-not-configured The tenant has no key protection backend A tenant administrator configures it
413 .../errors/payload-too-large The plaintext is above the one-request limit Use the streaming operation, or let encryptFile choose
422 with the detail "Unable to decrypt: key mismatch or ciphertext integrity failure." The tag does not verify, the JWE was edited, its key confirmation is missing or does not match the recipient Do not use the data; obtain the original JWE
422 with an extensions.errorCode such as JWE_ROOT_MEMBER_FORBIDDEN or JOSE_ACTOR_KID_REPEATED The JWE carries a member or a shape the platform does not accept Send the JWE as the platform produced it
400 naming recipientKid The JWE is addressed to several keys and no recipient, or a recipient it does not have, was named Name one of its recipients
Streaming decrypt ends with verdict INVALID and no content The ciphertext or its header was altered, or the key confirmation failed Discard the output; the SDK raises StreamIntegrityException and writes no file
400 .../errors/pqc-transport-not-available-for-streaming A streaming request was sent with PQC session transport Resend without the X-PQC-Transport and X-PQC-Session headers
503 .../errors/key-protection-backend-unavailable The key protection backend is temporarily unavailable Retry after Retry-After

Without the console

These operations have no console screen.

Surface How
Java SDK encrypt, encryptFile, encryptFileStream, decrypt, decryptFile, decryptFileStream on AuthenticatedSdk
Crypto CLI AnkaSecureCLI encrypt-file, decrypt-file, encrypt-file-stream, decrypt-file-stream
API POST /api/v3/crypto/encrypt (encryptData), POST /api/v3/crypto/decrypt (decryptData), POST /api/v3/crypto/stream/encrypt (encryptStream), POST /api/v3/crypto/stream/decrypt (decryptStream)