Skip to content

Client-Side Encryption

AnonPaste supports client-side encryption for pastes and files. The content is encrypted before it reaches the API — the server stores only ciphertext.

This means:

  • AnonPaste cannot read your content
  • If the server is compromised, your data remains protected
  • Only someone with the encryption key can decrypt it

The SDK uses AES-256-CBC with a key derived by SHA-256 hashing your password. This is the same scheme used internally by AnonPaste for encrypted pastes.

key = SHA256(password)
iv = be410fea41df7162a679875ec131cf2c (fixed)
mode = AES-256-CBC
pad = PKCS7

The SDK compresses the text with lz-string first, then encrypts it:

const { id } = await anonpaste.pastes.encryptAndCreate({
name: 'My Secret Notes',
text: 'This content is encrypted end-to-end.',
encryptionKey: 'my-strong-passphrase',
// Optional: control visibility and expiry
mode: PasteMode.Private,
neverExpire: true,
});
const paste = await anonpaste.pastes.getAndDecrypt(id, 'my-strong-passphrase');
console.log(paste.decryptedText); // original plaintext

If you’re not using the SDK, you must handle compression and encryption yourself:

  1. Compress the text with lz-string (compressToBase64)
  2. Encrypt with AES-256-CBC (key = SHA256 of password, fixed IV above)
  3. Send the ciphertext as the text field
Terminal window
# The text field must be the AES-CBC encrypted, lz-compressed ciphertext
curl -X POST https://api.anonpaste.com/api/dev/pastes/create \
-H "x-api-key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Encrypted Paste",
"text": "<base64-encoded-ciphertext>",
"mode": 0
}'

Encrypts the file client-side before uploading:

import { readFileSync } from 'fs';
const { fileId, readUrl } = await anonpaste.files.uploadEncrypted({
fileName: 'sensitive.pdf',
contentType: 'application/pdf',
fileData: readFileSync('./sensitive.pdf'),
encryptionKey: 'my-strong-passphrase',
});

The uploaded blob is opaque to the server. To decrypt it after downloading:

import { decryptBuffer } from 'anonpaste-sdk';
const { readUrl } = await anonpaste.files.get(fileId);
const response = await fetch(readUrl);
const encrypted = await response.text(); // base64 ciphertext
const decrypted = decryptBuffer(encrypted, 'my-strong-passphrase');
// decrypted is a Uint8Array containing the original file bytes

All encryption functions are exported at the top level of the SDK:

import { encryptText, decryptText, encryptBuffer, decryptBuffer } from 'anonpaste-sdk';
// Text
const ciphertext = encryptText('hello world', 'my-key');
const plaintext = decryptText(ciphertext, 'my-key');
// Binary (Buffer / Uint8Array)
const encryptedBlob = encryptBuffer(someBuffer, 'my-key'); // returns base64 string
const originalBytes = decryptBuffer(encryptedBlob, 'my-key'); // returns Uint8Array
import { compressToBase64, decompressFromBase64 } from 'anonpaste-sdk';
const compressed = compressToBase64('long text...');
const decompressed = decompressFromBase64(compressed);

  • Use strong passphrases — the security of your encrypted content depends entirely on key strength
  • Never send the key to the server — the SDK ensures keys only exist in your code
  • Store keys separately from ciphertext — if you store the key alongside the encrypted data, you lose the security benefit
  • Use different keys per resource — a single compromised key should only affect one resource