Kyndex

Document Upload With Client-Side Encryption

Upload an encrypted document, wrap its key material, wait for enclave processing, and verify searchability.

Documents are encrypted before upload. Literal stores encrypted content, wrapped keys, blind index tokens, and operational metadata. The application server does not receive document plaintext, plaintext metadata, or plaintext search terms.

Prerequisites

Before starting, the client needs:

  • An active access token.
  • Client-side cryptography for authenticated encryption, key wrapping, and blind index token generation.
  • The current platform public key for platform-wrapped document keys.

See Authentication and Platform Keys.

Overview

Loading diagram…
StepWhereOutput
Get platform keyLiteral → clientpublic key for platform wrapping
Reserve slotLiteral → clientdocument ID and commitment nonce
Encrypt locallyclientencrypted content, encrypted metadata, wrapped keys, blind tokens
Create recordclient → Literaldocument metadata record in pending_upload
Upload contentclient → Literalencrypted binary content
Processenclaveverification artifacts and encrypted outputs
Verify searchabilityclient + Literalencrypted search results

Endpoint sequence:

  • GET /v1/public-keys/server
  • POST /v1/documents/reservations
  • POST /v1/documents
  • PUT /v1/documents/{id}/content
  • GET /v1/documents/{id}
  • POST /v1/search

Use the API Reference for exact request fields, response bodies, and errors.

Step 1 — Get The Platform Public Key

The client fetches the current platform public key before encryption. This key is used to wrap the document encryption key for enclave processing.

Endpoint: GET /v1/public-keys/server

Cache the key and refresh it when key rotation requires a new one. See Platform Keys.

Step 2 — Reserve A Document Slot

Reservation gives the client a server-authoritative document ID and a commitment nonce that binds encryption to this specific upload. The reservation expires in 5 minutes.

Two-phase upload gives Literal a server-authoritative document ID before encryption and binds the encrypted content to that reservation through the commitment nonce.

Reserve before encrypting. The commitment_nonce from the reservation must be included in the encryption AAD so the ciphertext is bound to this document slot.

Endpoint: POST /v1/documents/reservations

Use the reservation’s document ID as the reservation_id in Step 4.

Step 3 — Encrypt The Document Locally

The client performs five operations before creating the document record.

Generate A Document Encryption Key

Create a fresh, random symmetric encryption key for this document. Every document has its own unique key — no two documents share a key.

Encrypt Content And Metadata

Encrypt the document bytes and the document metadata (title, filename, type, tags) separately using the document encryption key with authenticated encryption. Include the commitment_nonce from Step 2 and the key-wrapping timestamp (wrap_ts) in the AEAD authentication context to bind the ciphertext to this specific upload.

Wrap The Document Key

Wrap the document encryption key twice:

  1. With the document holder’s personal master key, so the holder can decrypt the document later.
  2. With the platform public key from Step 1, so the secure enclave can process the document.

Both wraps target the same plaintext document key. Literal stores both wrapped copies but does not receive the unwrapped key.

Generate Blind Index Tokens

Generate one-way cryptographic tokens for each searchable value (document type, text content, dates, tags). Each token is computed using the personal search key and a normalization step that ensures consistent matching. See Encrypted Search and Key Hierarchy for the underlying model.

Prepare Upload Metadata

Compute the owner and document tokens for blind routing, capture the wrapping timestamp, and select a coarse size bucket for the encrypted content. These values accompany the document record in Step 4.

Step 4 — Create The Document Record

The create request stores the encrypted document metadata and access material. It includes:

  • the reservation ID
  • encrypted metadata
  • document key wrapped for personal access
  • document key wrapped for platform/enclave processing
  • owner and document tokens for blind routing
  • optional personal search tokens
  • size bucket and wrapping timestamp

Endpoint: POST /v1/documents

After this step, the record is created in pending_upload and waits for the encrypted content upload.

Step 5 — Upload Encrypted Content

Upload the encrypted document bytes as binary content.

Endpoint: PUT /v1/documents/{id}/content

The upload must include the encrypted bytes and a valid content length. After upload, the document enters the processing queue.

The maximum upload size is 100 MB. The 10 MB threshold affects download behavior only; it does not change upload behavior.

During processing, the secure enclave unwraps the document key, temporarily decrypts the document, performs verification and seal generation, and returns encrypted outputs. The application server stores those outputs but does not receive document plaintext.

Step 6 — Confirm Enclave Processing

After upload, the document moves through several processing states automatically. Poll the document status to track progress.

Endpoint: GET /v1/documents/{id}

Document Processing States

StateDescription
pending_uploadRecord created, waiting for encrypted content.
pending_ocrContent uploaded, queued for enclave processing.
processingSecure enclave is actively processing the document.
processedEnclave processing complete — verification seal generated.
failedProcessing failed — the document must be re-uploaded.

Processing status and searchability are related but not identical. A document is searchable only after the relevant blind index tokens exist for that scope.

For a deeper look at what happens at each stage, see Document Lifecycle.

Step 7 — Verify Searchability

After processing, generate a search token locally using the same search key and normalization rules used during indexing.

Endpoint: POST /v1/search

Literal matches the token and returns encrypted records. The client decrypts the returned metadata and document key material locally.

See Encrypted Search for the search workflow.

Troubleshooting

  • If a reservation expires, create a new reservation and re-encrypt with the new commitment nonce.
  • If upload fails after record creation, retry according to the document state returned by the API.
  • If the document remains in a processing state, poll with backoff.
  • If search returns no results, confirm that the relevant blind index tokens exist for the search scope.

See Error Handling and the API Reference for status-specific errors.

Last updated on

On this page