Skip to main content
Payload encryption provides an additional encryption layer on top of standard TLS to support end-to-end privacy in scenarios such as man-in-the-middle attacks. This feature encrypts the uploaded file bytes before uploading to the presigned URL.
This is an optional feature and requires configuration parameters from Resistant AI.

How it works (high level)

  1. You create a submission (standard flow).
  2. The API returns a presigned upload URL.
  3. You create a JWE compact encrypted payload from the original file bytes.
  4. You upload the encrypted payload to the presigned URL (same upload step, different request body).
  5. Resistant AI fetches the encrypted payload from object storage, decrypts it, and processes the file.
Payload Encryption Api Calls

Encryption format and algorithms

Payload encryption uses the JWE (JSON Web Encryption) standard in compact format with asymmetric key wrapping of the content encryption key (CEK). Supported algorithms:
  • Key management: RSA-OAEP-256
  • Content encryption: A256GCM (AES-256-GCM)

JOSE header requirements

Your JWE protected header must follow JOSE header rules and include: Example header:
{
  "alg": "RSA-OAEP-256",
  "enc": "A256GCM",
  "zip": "DEF",
  "kid": "<RESISTANT_AI_RSA_KID>"
}
  • alg (required): fixed to supported algorithm (RSA-OAEP-256) 
  • enc (required): fixed to supported encryption (A256GCM) 
  • kid (required): key identifier used for key rotation (provided by Resistant AI) 
  • zip (optional): compression algorithm applied before encryption; recommended to speed up transfer 
Header values must correspond to the actual JWE message; incorrect values can prevent decryption. 

Supported endpoints

Payload encryption currently applies to:
  • Data upload via presigned URL (only the upload request body differs; other parameters remain the same). 

Key rotation (kid)

Key rotation is supported using the kid header field.  Key rotation rules:
  • You must send the kid that matches the public key you use for encryption. 
  • When keys rotate, you must update both:
    • kid
    • the public key used for encryption 
  • Resistant AI provides:
    • new kid
    • new public key
    • timeline and transition period (old + new key valid for a period). 
If kid does not correspond to the public key used, decryption will fail on the Resistant AI side. 

Configuration required from Resistant AI

Configuration is specific per stage (testing vs production) and cell/region, and includes: 
  • Public key (public part of the asymmetric key)
  • Key ID (kid) corresponding to that public key
  • Key spec of the asymmetric key

Example implementation (Python)

Any RFC 7516 compatible JWE library can be used.  Example (Authlib JOSE) from the documentation: 
from authlib.jose import JsonWebEncryption

jwe = JsonWebEncryption()
RESISTANT_AI_RSA_KID = "TODO: input here"

with open('resistant_ai_rsa_public.pem', 'rb') as f:
    key = f.read()

with open('testing_file.pdf', "rb") as fp:
    payload = fp.read()

protected = {
    'alg': 'RSA-OAEP-256',
    'enc': 'A256GCM',
    'zip': 'DEF',
    'kid': RESISTANT_AI_RSA_KID
}

encrypted_upload_request_payload = jwe.serialize_compact(protected, payload, key)

# send encrypted_upload_request_payload to the presigned upload URL as request body

Operational guidance

  • Treat payload encryption as a per-environment configuration (testing/prod keys differ). 
  • Log only non-sensitive metadata (submission_id, timestamp, kid, environment). Do not log ciphertext or keys.
  • Plan a key rotation procedure (update public key + kid during the transition window).