@techbulls/encrypted-s3-store 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -8
- package/dist/client.d.ts +23 -4
- package/dist/client.js +77 -12
- package/dist/types.d.ts +59 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ A TypeScript library that provides transparent end-to-end encryption for AWS S3
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **AES-256-GCM Encryption** - Military-grade encryption for all stored objects
|
|
8
|
+
- **Custom Encryption Support** - Bring your own encryption/decryption functions
|
|
8
9
|
- **Configurable Modes** - Choose between `encrypt` (with encryption) or `passthrough` (without encryption)
|
|
9
10
|
- **Scrypt Key Derivation** - Secure memory-hard key derivation using Node.js built-in crypto
|
|
10
11
|
- **Transparent Encryption/Decryption** - Automatic handling during upload and download
|
|
@@ -64,11 +65,12 @@ const result = await store.download({
|
|
|
64
65
|
|
|
65
66
|
The `S3ObjectStore` constructor accepts the following parameters:
|
|
66
67
|
|
|
67
|
-
| Parameter
|
|
68
|
-
|
|
|
69
|
-
| `client`
|
|
70
|
-
| `key`
|
|
71
|
-
| `mode`
|
|
68
|
+
| Parameter | Type | Required | Description |
|
|
69
|
+
| ------------------ | ------------------ | -------- | --------------------------------------------------------------------- |
|
|
70
|
+
| `client` | `S3Client` | Yes | An initialized AWS S3Client instance |
|
|
71
|
+
| `key` | `string` | Yes\* | Encryption key for AES-256-GCM or custom encryption |
|
|
72
|
+
| `mode` | `ModeType` | No | Operation mode (`'encrypt'` or `'passthrough'`). Default: `'encrypt'` |
|
|
73
|
+
| `customEncryption` | `CustomEncryption` | No | Custom encrypt/decrypt functions to replace default AES-256-GCM |
|
|
72
74
|
|
|
73
75
|
\*Required when using `encrypt` mode. Can also be provided via `ENCRYPTION_KEY` environment variable.
|
|
74
76
|
|
|
@@ -250,6 +252,77 @@ const result = await store.download({
|
|
|
250
252
|
});
|
|
251
253
|
```
|
|
252
254
|
|
|
255
|
+
### Custom Encryption
|
|
256
|
+
|
|
257
|
+
You can provide your own encryption/decryption functions to replace the default AES-256-GCM implementation:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { S3ObjectStore, CustomEncryption } from '@techbulls/encrypted-s3-store';
|
|
261
|
+
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
|
|
262
|
+
|
|
263
|
+
const customEncryption: CustomEncryption = {
|
|
264
|
+
encrypt: (data: Buffer, key: string) => {
|
|
265
|
+
// Your custom encryption logic
|
|
266
|
+
const iv = randomBytes(16);
|
|
267
|
+
const cipher = createCipheriv('aes-256-cbc', Buffer.from(key.padEnd(32)), iv);
|
|
268
|
+
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
data: encrypted,
|
|
272
|
+
metadata: {
|
|
273
|
+
iv: iv.toString('base64'),
|
|
274
|
+
algorithm: 'aes-256-cbc',
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
decrypt: (data: Buffer, key: string, metadata) => {
|
|
279
|
+
// Your custom decryption logic using the metadata
|
|
280
|
+
const iv = Buffer.from(metadata.iv, 'base64');
|
|
281
|
+
const decipher = createDecipheriv('aes-256-cbc', Buffer.from(key.padEnd(32)), iv);
|
|
282
|
+
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const store = new S3ObjectStore(s3Client, 'my-secret-key', 'encrypt', customEncryption);
|
|
287
|
+
|
|
288
|
+
// Upload using custom encryption
|
|
289
|
+
await store.upload({
|
|
290
|
+
Bucket: 'my-bucket',
|
|
291
|
+
Key: 'file.txt',
|
|
292
|
+
Body: 'Sensitive data',
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Download using custom decryption
|
|
296
|
+
const result = await store.download({
|
|
297
|
+
Bucket: 'my-bucket',
|
|
298
|
+
Key: 'file.txt',
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Custom Encryption Interface:**
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
interface CustomEncryption {
|
|
306
|
+
encrypt: (data: Buffer, key: string) => EncryptResult | Promise<EncryptResult>;
|
|
307
|
+
decrypt: (data: Buffer, key: string, metadata: EncryptionMetadata) => Buffer | Promise<Buffer>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface EncryptResult {
|
|
311
|
+
data: Buffer; // The encrypted data
|
|
312
|
+
metadata: EncryptionMetadata; // Metadata to store for decryption
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
interface EncryptionMetadata {
|
|
316
|
+
[key: string]: string; // Key-value pairs stored in S3 object metadata
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Notes:**
|
|
321
|
+
- Both `encrypt` and `decrypt` functions must be provided together
|
|
322
|
+
- Metadata keys are automatically prefixed with `x-amz-custom-` when stored in S3
|
|
323
|
+
- Custom encryption uses `x-amz-encryption: 'custom'` as the marker in S3 metadata
|
|
324
|
+
- Functions can be synchronous or asynchronous (return Promise)
|
|
325
|
+
|
|
253
326
|
### Environment-based Configuration
|
|
254
327
|
|
|
255
328
|
```typescript
|
|
@@ -282,10 +355,15 @@ Uses scrypt with the following parameters:
|
|
|
282
355
|
|
|
283
356
|
Encryption metadata is stored in S3 object metadata:
|
|
284
357
|
|
|
358
|
+
**Default AES-256-GCM:**
|
|
285
359
|
- `x-amz-iv` - Base64-encoded initialization vector
|
|
286
360
|
- `x-amz-salt` - Base64-encoded salt for key derivation
|
|
287
361
|
- `x-amz-auth-tag` - Base64-encoded authentication tag
|
|
288
|
-
- `x-amz-encryption` -
|
|
362
|
+
- `x-amz-encryption` - Set to `aes-256-gcm`
|
|
363
|
+
|
|
364
|
+
**Custom Encryption:**
|
|
365
|
+
- `x-amz-custom-*` - Custom metadata keys (prefixed automatically)
|
|
366
|
+
- `x-amz-encryption` - Set to `custom`
|
|
289
367
|
|
|
290
368
|
## Error Handling
|
|
291
369
|
|
|
@@ -308,7 +386,16 @@ The library is written in TypeScript and exports all types:
|
|
|
308
386
|
|
|
309
387
|
```typescript
|
|
310
388
|
import { S3ObjectStore } from '@techbulls/encrypted-s3-store';
|
|
311
|
-
import type {
|
|
389
|
+
import type {
|
|
390
|
+
ModeType,
|
|
391
|
+
IUpload,
|
|
392
|
+
IDownload,
|
|
393
|
+
CustomEncryption,
|
|
394
|
+
EncryptFunction,
|
|
395
|
+
DecryptFunction,
|
|
396
|
+
EncryptResult,
|
|
397
|
+
EncryptionMetadata,
|
|
398
|
+
} from '@techbulls/encrypted-s3-store';
|
|
312
399
|
import type { PutObjectCommandInput, GetObjectCommandInput } from '@techbulls/encrypted-s3-store';
|
|
313
400
|
```
|
|
314
401
|
|
|
@@ -350,4 +437,4 @@ await store.client.send(
|
|
|
350
437
|
|
|
351
438
|
## License
|
|
352
439
|
|
|
353
|
-
Licensed under the
|
|
440
|
+
Licensed under the MIT License. See [LICENSE.md](LICENSE.md) for details.
|
package/dist/client.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @license Apache-2.0
|
|
7
7
|
*/
|
|
8
8
|
import { S3Client } from '@aws-sdk/client-s3';
|
|
9
|
-
import { IDownload, IUpload, ModeType } from './types.js';
|
|
9
|
+
import { CustomEncryption, IDownload, IUpload, ModeType } from './types.js';
|
|
10
10
|
import { Readable } from 'node:stream';
|
|
11
11
|
/**
|
|
12
12
|
* S3 client wrapper with transparent end-to-end encryption support.
|
|
@@ -40,12 +40,15 @@ export declare class S3ObjectStore {
|
|
|
40
40
|
algorithm: string;
|
|
41
41
|
/** @type {S3Client} The underlying AWS S3 client instance */
|
|
42
42
|
client: S3Client;
|
|
43
|
+
/** @type {CustomEncryption | undefined} Optional custom encryption/decryption functions */
|
|
44
|
+
customEncryption?: CustomEncryption;
|
|
43
45
|
/**
|
|
44
46
|
* Creates a new S3ObjectStore instance.
|
|
45
47
|
*
|
|
46
48
|
* @param client - An initialized AWS S3Client instance
|
|
47
49
|
* @param key - Encryption key for AES-256-GCM. Falls back to ENCRYPTION_KEY environment variable if not provided.
|
|
48
50
|
* @param mode - Operation mode ('encrypt' or 'passthrough'). Defaults to 'encrypt'.
|
|
51
|
+
* @param customEncryption - Optional custom encryption/decryption functions to replace the default AES-256-GCM implementation.
|
|
49
52
|
* @throws {Error} If no encryption key is provided and ENCRYPTION_KEY environment variable is not set
|
|
50
53
|
*
|
|
51
54
|
* @example
|
|
@@ -58,13 +61,24 @@ export declare class S3ObjectStore {
|
|
|
58
61
|
*
|
|
59
62
|
* // With passthrough mode (no encryption)
|
|
60
63
|
* const store = new S3ObjectStore(s3Client, 'key', 'passthrough');
|
|
64
|
+
*
|
|
65
|
+
* // With custom encryption
|
|
66
|
+
* const store = new S3ObjectStore(s3Client, 'key', 'encrypt', {
|
|
67
|
+
* encrypt: (data, key) => ({ data: myEncrypt(data, key), metadata: { myParam: '...' } }),
|
|
68
|
+
* decrypt: (data, key, metadata) => myDecrypt(data, key, metadata.myParam)
|
|
69
|
+
* });
|
|
61
70
|
* ```
|
|
62
71
|
*/
|
|
63
|
-
constructor(client: S3Client, key?: string, mode?: ModeType);
|
|
72
|
+
constructor(client: S3Client, key?: string, mode?: ModeType, customEncryption?: CustomEncryption);
|
|
64
73
|
/**
|
|
65
74
|
* Uploads data to S3 with optional encryption.
|
|
66
75
|
*
|
|
67
|
-
* In 'encrypt' mode:
|
|
76
|
+
* In 'encrypt' mode with custom encryption:
|
|
77
|
+
* - Calls the custom encrypt function with data and key
|
|
78
|
+
* - Stores returned metadata with 'x-amz-custom-' prefix in S3 object metadata
|
|
79
|
+
* - Sets 'x-amz-encryption' to 'custom'
|
|
80
|
+
*
|
|
81
|
+
* In 'encrypt' mode (default AES-256-GCM):
|
|
68
82
|
* - Generates a random 12-byte IV (Initialization Vector)
|
|
69
83
|
* - Generates a random 16-byte salt for key derivation
|
|
70
84
|
* - Derives a 256-bit key using scrypt
|
|
@@ -109,7 +123,12 @@ export declare class S3ObjectStore {
|
|
|
109
123
|
/**
|
|
110
124
|
* Downloads data from S3 with optional decryption.
|
|
111
125
|
*
|
|
112
|
-
* In 'encrypt' mode:
|
|
126
|
+
* In 'encrypt' mode with custom encryption (x-amz-encryption: 'custom'):
|
|
127
|
+
* - Extracts custom metadata (removes 'x-amz-custom-' prefix)
|
|
128
|
+
* - Buffers the encrypted stream
|
|
129
|
+
* - Calls the custom decrypt function with data, key, and metadata
|
|
130
|
+
*
|
|
131
|
+
* In 'encrypt' mode (default AES-256-GCM):
|
|
113
132
|
* - Retrieves encryption metadata (IV, salt, auth tag) from S3 object metadata
|
|
114
133
|
* - Derives the decryption key using scrypt with the stored salt
|
|
115
134
|
* - Decrypts the data using AES-256-GCM
|
package/dist/client.js
CHANGED
|
@@ -37,6 +37,7 @@ export class S3ObjectStore {
|
|
|
37
37
|
* @param client - An initialized AWS S3Client instance
|
|
38
38
|
* @param key - Encryption key for AES-256-GCM. Falls back to ENCRYPTION_KEY environment variable if not provided.
|
|
39
39
|
* @param mode - Operation mode ('encrypt' or 'passthrough'). Defaults to 'encrypt'.
|
|
40
|
+
* @param customEncryption - Optional custom encryption/decryption functions to replace the default AES-256-GCM implementation.
|
|
40
41
|
* @throws {Error} If no encryption key is provided and ENCRYPTION_KEY environment variable is not set
|
|
41
42
|
*
|
|
42
43
|
* @example
|
|
@@ -49,9 +50,15 @@ export class S3ObjectStore {
|
|
|
49
50
|
*
|
|
50
51
|
* // With passthrough mode (no encryption)
|
|
51
52
|
* const store = new S3ObjectStore(s3Client, 'key', 'passthrough');
|
|
53
|
+
*
|
|
54
|
+
* // With custom encryption
|
|
55
|
+
* const store = new S3ObjectStore(s3Client, 'key', 'encrypt', {
|
|
56
|
+
* encrypt: (data, key) => ({ data: myEncrypt(data, key), metadata: { myParam: '...' } }),
|
|
57
|
+
* decrypt: (data, key, metadata) => myDecrypt(data, key, metadata.myParam)
|
|
58
|
+
* });
|
|
52
59
|
* ```
|
|
53
60
|
*/
|
|
54
|
-
constructor(client, key, mode) {
|
|
61
|
+
constructor(client, key, mode, customEncryption) {
|
|
55
62
|
/** @type {string} Encryption algorithm identifier (always 'aes-256-gcm') */
|
|
56
63
|
this.algorithm = 'aes-256-gcm';
|
|
57
64
|
this.client = client;
|
|
@@ -61,11 +68,17 @@ export class S3ObjectStore {
|
|
|
61
68
|
}
|
|
62
69
|
this.key = (key || envEncryptionKey);
|
|
63
70
|
this.mode = mode ?? 'encrypt';
|
|
71
|
+
this.customEncryption = customEncryption;
|
|
64
72
|
}
|
|
65
73
|
/**
|
|
66
74
|
* Uploads data to S3 with optional encryption.
|
|
67
75
|
*
|
|
68
|
-
* In 'encrypt' mode:
|
|
76
|
+
* In 'encrypt' mode with custom encryption:
|
|
77
|
+
* - Calls the custom encrypt function with data and key
|
|
78
|
+
* - Stores returned metadata with 'x-amz-custom-' prefix in S3 object metadata
|
|
79
|
+
* - Sets 'x-amz-encryption' to 'custom'
|
|
80
|
+
*
|
|
81
|
+
* In 'encrypt' mode (default AES-256-GCM):
|
|
69
82
|
* - Generates a random 12-byte IV (Initialization Vector)
|
|
70
83
|
* - Generates a random 16-byte salt for key derivation
|
|
71
84
|
* - Derives a 256-bit key using scrypt
|
|
@@ -120,14 +133,6 @@ export class S3ObjectStore {
|
|
|
120
133
|
}));
|
|
121
134
|
}
|
|
122
135
|
/** Encrypt mode: encrypt data before uploading */
|
|
123
|
-
/** @type {Buffer} iv - 96-bit IV for GCM mode */
|
|
124
|
-
const iv = randomBytes(12);
|
|
125
|
-
/** @type {Buffer} salt - 128-bit salt for scrypt key derivation */
|
|
126
|
-
const salt = randomBytes(16);
|
|
127
|
-
/** Derive encryption key using scrypt (memory-hard, resistant to GPU attacks) */
|
|
128
|
-
const secretKey = await deriveKey(this.key, salt);
|
|
129
|
-
/** Create AES-256-GCM cipher */
|
|
130
|
-
const cipher = createCipheriv('aes-256-gcm', secretKey, iv);
|
|
131
136
|
/** Convert input body to Buffer for encryption */
|
|
132
137
|
let data;
|
|
133
138
|
if (typeof input.Body === 'string') {
|
|
@@ -142,6 +147,36 @@ export class S3ObjectStore {
|
|
|
142
147
|
else {
|
|
143
148
|
throw new Error('Unsupported Body type: only string, Buffer, or Uint8Array supported');
|
|
144
149
|
}
|
|
150
|
+
/** Use custom encryption if provided */
|
|
151
|
+
if (this.customEncryption) {
|
|
152
|
+
const result = await this.customEncryption.encrypt(data, this.key);
|
|
153
|
+
/** Prefix custom metadata keys to avoid conflicts */
|
|
154
|
+
const customMetadata = {};
|
|
155
|
+
for (const [key, value] of Object.entries(result.metadata)) {
|
|
156
|
+
customMetadata[`x-amz-custom-${key}`] = value;
|
|
157
|
+
}
|
|
158
|
+
return this.client.send(new PutObjectCommand({
|
|
159
|
+
...input,
|
|
160
|
+
Bucket: input.Bucket || this.bucket,
|
|
161
|
+
Body: result.data,
|
|
162
|
+
ContentLength: result.data.length,
|
|
163
|
+
Metadata: {
|
|
164
|
+
...(input.Metadata || {}),
|
|
165
|
+
...customMetadata,
|
|
166
|
+
/** @description Marker indicating custom encryption was used */
|
|
167
|
+
'x-amz-encryption': 'custom',
|
|
168
|
+
},
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
/** Default AES-256-GCM encryption */
|
|
172
|
+
/** @type {Buffer} iv - 96-bit IV for GCM mode */
|
|
173
|
+
const iv = randomBytes(12);
|
|
174
|
+
/** @type {Buffer} salt - 128-bit salt for scrypt key derivation */
|
|
175
|
+
const salt = randomBytes(16);
|
|
176
|
+
/** Derive encryption key using scrypt (memory-hard, resistant to GPU attacks) */
|
|
177
|
+
const secretKey = await deriveKey(this.key, salt);
|
|
178
|
+
/** Create AES-256-GCM cipher */
|
|
179
|
+
const cipher = createCipheriv('aes-256-gcm', secretKey, iv);
|
|
145
180
|
/** Encrypt the data */
|
|
146
181
|
const encryptedBody = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
147
182
|
/** Get the GCM authentication tag (ensures data integrity and authenticity) */
|
|
@@ -168,7 +203,12 @@ export class S3ObjectStore {
|
|
|
168
203
|
/**
|
|
169
204
|
* Downloads data from S3 with optional decryption.
|
|
170
205
|
*
|
|
171
|
-
* In 'encrypt' mode:
|
|
206
|
+
* In 'encrypt' mode with custom encryption (x-amz-encryption: 'custom'):
|
|
207
|
+
* - Extracts custom metadata (removes 'x-amz-custom-' prefix)
|
|
208
|
+
* - Buffers the encrypted stream
|
|
209
|
+
* - Calls the custom decrypt function with data, key, and metadata
|
|
210
|
+
*
|
|
211
|
+
* In 'encrypt' mode (default AES-256-GCM):
|
|
172
212
|
* - Retrieves encryption metadata (IV, salt, auth tag) from S3 object metadata
|
|
173
213
|
* - Derives the decryption key using scrypt with the stored salt
|
|
174
214
|
* - Decrypts the data using AES-256-GCM
|
|
@@ -214,10 +254,35 @@ export class S3ObjectStore {
|
|
|
214
254
|
/** Encrypt mode: decrypt the response */
|
|
215
255
|
/** Extract encryption metadata from S3 object */
|
|
216
256
|
const metadata = response.Metadata || {};
|
|
257
|
+
const encryption = metadata['x-amz-encryption'];
|
|
258
|
+
/** Handle custom encryption */
|
|
259
|
+
if (encryption === 'custom' && this.customEncryption) {
|
|
260
|
+
/** Extract custom metadata (remove x-amz-custom- prefix) */
|
|
261
|
+
const customMetadata = {};
|
|
262
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
263
|
+
if (key.startsWith('x-amz-custom-')) {
|
|
264
|
+
customMetadata[key.replace('x-amz-custom-', '')] = value;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Buffer the stream to get the encrypted data */
|
|
268
|
+
const chunks = [];
|
|
269
|
+
for await (const chunk of response.Body) {
|
|
270
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
271
|
+
}
|
|
272
|
+
const encryptedData = Buffer.concat(chunks);
|
|
273
|
+
/** Decrypt using custom decryption function */
|
|
274
|
+
const decryptedData = await this.customEncryption.decrypt(encryptedData, this.key, customMetadata);
|
|
275
|
+
return {
|
|
276
|
+
Body: Readable.from(decryptedData),
|
|
277
|
+
ContentType: response.ContentType,
|
|
278
|
+
ContentLength: response.ContentLength,
|
|
279
|
+
Metadata: response.Metadata,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/** Default AES-256-GCM decryption */
|
|
217
283
|
const ivBase64 = metadata['x-amz-iv'];
|
|
218
284
|
const saltBase64 = metadata['x-amz-salt'];
|
|
219
285
|
const authTagBase64 = metadata['x-amz-auth-tag'];
|
|
220
|
-
const encryption = metadata['x-amz-encryption'];
|
|
221
286
|
/** If encryption metadata is missing, return unencrypted stream */
|
|
222
287
|
if (!ivBase64 || !saltBase64 || !authTagBase64 || encryption !== 'aes-256-gcm') {
|
|
223
288
|
return {
|
package/dist/types.d.ts
CHANGED
|
@@ -53,3 +53,62 @@ export interface IUpload extends PutObjectCommandInput {
|
|
|
53
53
|
export interface IDownload extends GetObjectCommandInput {
|
|
54
54
|
Mode?: ModeType;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Metadata returned by custom encrypt function, stored in S3 object metadata.
|
|
58
|
+
* All values must be strings as they are stored in S3 metadata headers.
|
|
59
|
+
*/
|
|
60
|
+
export interface EncryptionMetadata {
|
|
61
|
+
[key: string]: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Result returned by custom encrypt function.
|
|
65
|
+
*
|
|
66
|
+
* @property data - The encrypted data as a Buffer
|
|
67
|
+
* @property metadata - Key-value pairs to be stored in S3 object metadata for decryption
|
|
68
|
+
*/
|
|
69
|
+
export interface EncryptResult {
|
|
70
|
+
data: Buffer;
|
|
71
|
+
metadata: EncryptionMetadata;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Custom encryption function signature.
|
|
75
|
+
*
|
|
76
|
+
* @param data - The plaintext data to encrypt
|
|
77
|
+
* @param key - The encryption key provided to S3ObjectStore
|
|
78
|
+
* @returns The encrypted data and metadata (can be sync or async)
|
|
79
|
+
*/
|
|
80
|
+
export type EncryptFunction = (data: Buffer, key: string) => Promise<EncryptResult> | EncryptResult;
|
|
81
|
+
/**
|
|
82
|
+
* Custom decryption function signature.
|
|
83
|
+
*
|
|
84
|
+
* @param data - The encrypted data to decrypt
|
|
85
|
+
* @param key - The encryption key provided to S3ObjectStore
|
|
86
|
+
* @param metadata - The metadata that was stored during encryption
|
|
87
|
+
* @returns The decrypted plaintext data (can be sync or async)
|
|
88
|
+
*/
|
|
89
|
+
export type DecryptFunction = (data: Buffer, key: string, metadata: EncryptionMetadata) => Promise<Buffer> | Buffer;
|
|
90
|
+
/**
|
|
91
|
+
* Custom encryption handler interface.
|
|
92
|
+
* Both encrypt and decrypt functions must be provided together.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const customEncryption: CustomEncryption = {
|
|
97
|
+
* encrypt: (data, key) => {
|
|
98
|
+
* const iv = crypto.randomBytes(16);
|
|
99
|
+
* const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
100
|
+
* const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
101
|
+
* return { data: encrypted, metadata: { iv: iv.toString('base64') } };
|
|
102
|
+
* },
|
|
103
|
+
* decrypt: (data, key, metadata) => {
|
|
104
|
+
* const iv = Buffer.from(metadata.iv, 'base64');
|
|
105
|
+
* const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
|
106
|
+
* return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
107
|
+
* }
|
|
108
|
+
* };
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export interface CustomEncryption {
|
|
112
|
+
encrypt: EncryptFunction;
|
|
113
|
+
decrypt: DecryptFunction;
|
|
114
|
+
}
|