Encryption
Apertur supports end-to-end encrypted uploads using RSA-OAEP key wrapping and AES-256-GCM encryption. Images are encrypted client-side before being sent to the server.
How It Works
The encryption flow uses a hybrid scheme: a random AES-256-GCM symmetric key encrypts the image, and the server's RSA public key wraps the AES key.
- Fetch the server's RSA public key from the encryption endpoint.
- Generate a random AES-256-GCM key and nonce on the client.
- Encrypt the image data with AES-256-GCM.
- Wrap the AES key using RSA-OAEP with the server's public key, then upload the ciphertext along with the wrapped key and nonce.
Get Server Key
/api/v1/encryption/server-keyRetrieve the server's RSA public key in PEM format. This key is used to wrap the AES session key.
curl https://api.apertur.ca/api/v1/encryption/server-key \
-H "Authorization: Bearer aptr_live_xxxx"
# Response:
# {
# "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----"
# }Encrypted Upload
The Node.js and PHP SDKs handle encryption automatically via imageEncrypted(). For other languages, implement the AES-256-GCM + RSA-OAEP flow manually.
# Encrypted uploads require client-side encryption.
# Use one of the SDKs for automatic encryption handling.
#
# Manual flow:
# 1. GET /api/v1/encryption/server-key → RSA public key
# 2. Generate a random AES-256-GCM key + 12-byte IV
# 3. Encrypt the image with AES-256-GCM (ciphertext includes the GCM tag)
# 4. Wrap the AES key with RSA-OAEP (SHA-256) using the server's public key
# 5. POST /api/v1/upload/:uuid/images with header "X-Aptr-Encrypted: default",
# sending a multipart "file" part whose contents are the JSON envelope:
# {"encryptedKey","iv","encryptedData","algorithm"} (base64-encoded fields)Security Note
Encrypted uploads ensure that image data is protected in transit and at rest. The server never sees the raw AES key — only the wrapped version that can be decrypted server-side.