The Digital Post Platform supports optional client-side encryption of message content before upload.
When client-side encryption is used, files are encrypted by the sending system before being uploaded to the storage bucket. The encryption key must be provided in the Create Delivery request using the encryptionKey field so the platform can decrypt and process the content.
This mechanism provides an additional security layer on top of transport and storage encryption.
Encryption is optional. Unencrypted files are also supported.
When encryption is enabled:
- Files are encrypted before upload
- Encrypted files are uploaded to storage
- The encryption key is provided in the
Create Deliveryrequest using theencryptionKeyfield - The platform decrypts files during processing
- Each file is re-encrypted for recipient access
Encryption applies to:
- Message bodies
- Attachments
Metadata and envelope files are not encrypted.
The platform supports the following encryption modes:
| Mode | Algorithm | Integrity Protection | Recommendation |
|---|---|---|---|
| GCM | AES-256-GCM | Yes | Preferred |
| CBC | AES-256-CBC | No | Legacy |
AES-256-GCM provides authenticated encryption and is the recommended mode.
AES-256-CBC does not include integrity protection. When CBC is used, a content hash should be provided in the envelope to detect corruption.
Client-side encryption may be used when:
- Regulatory requirements mandate sender-controlled encryption
- Additional security controls are required
- Content must be encrypted before leaving the sender environment
If these requirements do not apply, standard platform encryption is sufficient.
Encrypted files must be encoded in chunks.
The following limits apply:
| Parameter | Limit |
|---|---|
| Maximum chunk size | 1 MB |
| Maximum chunks | 20 |
| Maximum encoded file size | Approximately 20 MB |
Files exceeding these limits must be split before delivery.
Encrypted files must follow a specific binary encoding format.
The first byte indicates encryption mode:
| Value | Mode |
|---|---|
| 1 | AES-256-CBC |
| 2 | AES-256-GCM |
When using AES-256-GCM, files must be chunked.
Each chunk contains:
| Field | Size |
|---|---|
| Chunk size | 4 bytes |
| Nonce | 12 bytes |
| Encrypted data | Variable |
| Authentication tag | 16 bytes |
Encoding format:
- Encryption indicator byte (2)
- Chunk 1
- Chunk 2
- ...
- Chunk N
Each chunk is encoded as:
[Chunk Size][Nonce][Encrypted Data][Auth Tag]
When using AES-256-CBC:
| Field | Size |
|---|---|
| Encryption indicator | 1 byte |
| Initialization vector | 16 bytes |
| Encrypted data | Variable |
Encoding format:
[Indicator][IV][Encrypted Data]
CBC mode does not include authentication tags.
When encrypting files:
- A unique symmetric key must be generated per delivery
- The same key must be used for all encrypted files in that delivery
- The key must be securely stored by the sending system
- The key must be provided in the
Create Deliveryrequest as theencryptionKeyfield - The key must never be embedded in the file itself
If the encryptionKey provided in the delivery request does not match the key used to encrypt the files, the platform will fail the delivery during processing.
Key management is the responsibility of the sending system.
See Upload Content to S3. for details about including the encryptionKey field in the delivery request.
Encrypted files are referenced in envelopes in the same way as unencrypted files.
Example:
{
"body": {
"artifact": {
"name": "invoice-880942299.enc",
"filename": "invoice.pdf"
}
}
}The platform determines encryption based on file content encoding.
AES-256-GCM Reference Implementation (Node.js)
The following example demonstrates encryption and encoding using AES-256-GCM.
Prerequisites • Node.js • crypto module • fs module
const crypto = require('crypto');
const fs = require('fs');
const ALGORITHM = 'aes-256-gcm';
const ENCRYPTION_INDICATOR = 2;
const CHUNK_SIZE = 1024 * 1024;
const MAX_CHUNKS = 20;
// Replace with secure key storage
const KEY = crypto.randomBytes(32);
function generateNonce() {
return crypto.randomBytes(12);
}
function encryptChunk(data, key) {
const nonce = generateNonce();
const cipher = crypto.createCipheriv(ALGORITHM, key, nonce);
const encrypted = Buffer.concat([
cipher.update(data),
cipher.final()
]);
const authTag = cipher.getAuthTag();
return {
encrypted,
nonce,
authTag
};
}
function encryptAndEncodeData(data, key) {
const chunks = [];
for (let i = 0; i < data.length; i += CHUNK_SIZE) {
chunks.push(data.slice(i, i + CHUNK_SIZE));
}
if (chunks.length > MAX_CHUNKS) {
throw new Error('File exceeds maximum size');
}
const encodedChunks = chunks.map(chunk => {
const result = encryptChunk(chunk, key);
const size = Buffer.alloc(4);
size.writeUInt32BE(
result.encrypted.length +
result.nonce.length +
result.authTag.length
);
return Buffer.concat([
size,
result.nonce,
result.encrypted,
result.authTag
]);
});
return Buffer.concat([
Buffer.from([ENCRYPTION_INDICATOR]),
...encodedChunks
]);
}
// Example usage
const input = fs.readFileSync('input.pdf');
const encrypted = encryptAndEncodeData(input, KEY);
fs.writeFileSync('encrypted.bin', encrypted);
console.log('Encryption completed');When using GCM mode: • Authentication tags verify integrity • Corruption is detected automatically
When using CBC mode: • No integrity verification exists • Corruption may go undetected • Hash values should be provided in envelopes
GCM is strongly recommended.
The following table lists common encryption related errors and recommended actions.
| Error | Description | Typical Cause | Recommended Action |
|---|---|---|---|
| Invalid encoding | The encrypted file does not follow the required chunk format | Incorrect chunk structure or missing fields | Verify chunk size, nonce length, and authentication tag |
| Unsupported encryption mode | The encryption indicator is not recognized | Invalid first byte in encoded file | Ensure the correct encryption mode value is used |
| Decryption failure | The platform cannot decrypt the file | Incorrect encryption key | Verify that the correct key is provided in the delivery request |
| Authentication tag validation failed | Integrity verification failed (GCM mode) | Corrupted data or incorrect key | Regenerate the encrypted file and verify transmission |
| Corrupted encrypted content | File contents are incomplete or altered | Transmission error or storage corruption | Re-upload the encrypted file |
| File size limit exceeded | Encoded file exceeds platform limits | Too many chunks or oversized input file | Split the file or reduce file size |
| Duplicate nonce detected | Nonce reuse detected | Nonce generation not unique | Ensure each chunk uses a unique nonce |
| Missing encryption key | No key provided with delivery | Misconfigured delivery request | Include the encryption key in the delivery request |
| Invalid hash value | Content hash does not match decrypted data | Hash mismatch or incorrect encryption | Recalculate and update the hash |
If encrypted files fail to process:
- Verify encryption mode indicator
- Verify chunk structure
- Verify key correctness
- Check file size limits
- Validate nonce uniqueness
- Confirm envelope references
After encryption is configured, continue with:
- Upload Content to Storage
- Create Delivery
- Verify and Troubleshoot
- Monitor Processing Reports