wilcocrypt 2.1.1 → 2.2.1
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/.github/ISSUE_TEMPLATE/bug.md +72 -0
- package/.github/ISSUE_TEMPLATE/config.yml +6 -0
- package/.github/ISSUE_TEMPLATE/feature.yml +38 -0
- package/.github/dependabot.yml +11 -0
- package/CHANGELOG.md +100 -0
- package/DOCS.md +527 -0
- package/README.md +61 -65
- package/SECURITY.md +48 -0
- package/package.json +14 -8
- package/src/cli.js +57 -37
- package/src/wilcocrypt.js +429 -102
- package/types/wilcocrypt.d.ts +309 -24
package/DOCS.md
ADDED
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
# WilcoCrypt Documentation
|
|
2
|
+
|
|
3
|
+
Complete reference for the WilcoCrypt API, CLI, and binary format.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick Start](#quick-start)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [encryptData](#encryptdata)
|
|
13
|
+
- [decryptData](#decryptdata)
|
|
14
|
+
- [encryptFile](#encryptfile)
|
|
15
|
+
- [decryptFile](#decryptfile)
|
|
16
|
+
- [encryptDataAsync](#encryptdataasync)
|
|
17
|
+
- [decryptDataAsync](#decryptdataasync)
|
|
18
|
+
- [encryptFileAsync](#encryptfileasync)
|
|
19
|
+
- [decryptFileAsync](#decryptfileasync)
|
|
20
|
+
- [encryptFileStream](#encryptfilestream)
|
|
21
|
+
- [decryptFileStream](#decryptfilestream)
|
|
22
|
+
- [Internal Namespace (`_`)](#internal-namespace-_)
|
|
23
|
+
- [CLI Reference](#cli-reference)
|
|
24
|
+
- [Binary Payload Format](#binary-payload-format)
|
|
25
|
+
- [Error Handling](#error-handling)
|
|
26
|
+
- [TypeScript](#typescript)
|
|
27
|
+
- [Security Notes](#security-notes)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install wilcocrypt
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires Node.js 18 or later (uses `stream/promises` and `fs/promises`).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import wilcocrypt from "wilcocrypt";
|
|
45
|
+
|
|
46
|
+
// Encrypt a Buffer
|
|
47
|
+
const data = Buffer.from("Hello, world!");
|
|
48
|
+
const encrypted = wilcocrypt.encryptData(data, "my-password");
|
|
49
|
+
|
|
50
|
+
// Decrypt it back
|
|
51
|
+
const decrypted = wilcocrypt.decryptData(encrypted, "my-password");
|
|
52
|
+
console.log(decrypted.toString()); // Hello, world!
|
|
53
|
+
|
|
54
|
+
// Encrypt a file (writes file.txt.enc)
|
|
55
|
+
wilcocrypt.encryptFile("file.txt", "my-password");
|
|
56
|
+
|
|
57
|
+
// Decrypt a file (returns Buffer)
|
|
58
|
+
const contents = wilcocrypt.decryptFile("file.txt.enc", "my-password");
|
|
59
|
+
|
|
60
|
+
// Decrypt a file directly to disk
|
|
61
|
+
wilcocrypt.decryptFile("file.txt.enc", "my-password", "output.txt");
|
|
62
|
+
|
|
63
|
+
// Async API
|
|
64
|
+
const encryptedAsync = await wilcocrypt.encryptDataAsync(
|
|
65
|
+
Buffer.from("Hello!"),
|
|
66
|
+
"my-password",
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const decryptedAsync = await wilcocrypt.decryptDataAsync(
|
|
70
|
+
encryptedAsync,
|
|
71
|
+
"my-password",
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Async file API
|
|
75
|
+
await wilcocrypt.encryptFileAsync(
|
|
76
|
+
"file.txt",
|
|
77
|
+
"my-password",
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
await wilcocrypt.decryptFileAsync(
|
|
81
|
+
"file.txt.enc",
|
|
82
|
+
"my-password",
|
|
83
|
+
"output.txt",
|
|
84
|
+
);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## API Reference
|
|
90
|
+
|
|
91
|
+
### `encryptData(plaindata, password, gzip?)`
|
|
92
|
+
|
|
93
|
+
Encrypts a Buffer using password-based AES-256-GCM. The password is never stored; a random salt is generated for every encryption call.
|
|
94
|
+
|
|
95
|
+
| Parameter | Type | Default | Description |
|
|
96
|
+
| ----------- | --------- | ------- | ------------------------------------------ |
|
|
97
|
+
| `plaindata` | `Buffer` | — | Raw data to encrypt |
|
|
98
|
+
| `password` | `string` | — | Password for key derivation (min. 6 chars) |
|
|
99
|
+
| `gzip` | `boolean` | `true` | Compress data before encryption |
|
|
100
|
+
|
|
101
|
+
**Returns:** `Buffer` — the encrypted payload in the [binary format](#binary-payload-format).
|
|
102
|
+
|
|
103
|
+
**Throws:** `WilcoCryptError` with code `WEAK_PASSWORD` if the password is too short.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const encrypted = wilcocrypt.encryptData(Buffer.from("secret"), "passw0rd");
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### `decryptData(encryptedBuffer, password, gzip?)`
|
|
112
|
+
|
|
113
|
+
Decrypts a payload produced by `encryptData`. Validates the header and version before attempting decryption.
|
|
114
|
+
|
|
115
|
+
| Parameter | Type | Default | Description |
|
|
116
|
+
| ----------------- | --------- | ------- | ------------------------------- |
|
|
117
|
+
| `encryptedBuffer` | `Buffer` | — | Payload from `encryptData` |
|
|
118
|
+
| `password` | `string` | — | Password used during encryption |
|
|
119
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
120
|
+
|
|
121
|
+
**Returns:** `Buffer` — the original plaintext data.
|
|
122
|
+
|
|
123
|
+
**Throws:**
|
|
124
|
+
|
|
125
|
+
| Code | Reason |
|
|
126
|
+
| ------------------- | ---------------------------------------------- |
|
|
127
|
+
| `WEAK_PASSWORD` | Password shorter than 6 characters |
|
|
128
|
+
| `INVALID_HEADER` | Not a valid WilcoCrypt payload |
|
|
129
|
+
| `VERSION_MISMATCH` | Payload was encrypted with a different version |
|
|
130
|
+
| `DECRYPTION_FAILED` | Wrong password, tampered or corrupt data |
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
const plain = wilcocrypt.decryptData(encrypted, "passw0rd");
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### `encryptFile(filePath, password, gzip?)`
|
|
139
|
+
|
|
140
|
+
Reads a file, encrypts it, and writes the result to `<filePath>.enc`. Uses `encryptData` internally, so the entire file is loaded into memory. For large files, use [`encryptFileStream`](#encryptfilestream) instead.
|
|
141
|
+
|
|
142
|
+
| Parameter | Type | Default | Description |
|
|
143
|
+
| ---------- | --------- | ------- | --------------------------- |
|
|
144
|
+
| `filePath` | `string` | — | Path to the source file |
|
|
145
|
+
| `password` | `string` | — | Password for key derivation |
|
|
146
|
+
| `gzip` | `boolean` | `true` | Compress before encryption |
|
|
147
|
+
|
|
148
|
+
**Returns:** `void`
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
wilcocrypt.encryptFile("document.pdf", "passw0rd");
|
|
152
|
+
// Creates document.pdf.enc
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### `decryptFile(filePath, password, outputPath?, gzip?)`
|
|
158
|
+
|
|
159
|
+
Decrypts a `.enc` file. If `outputPath` is provided, the result is written to disk and `undefined` is returned. Otherwise the decrypted `Buffer` is returned.
|
|
160
|
+
|
|
161
|
+
| Parameter | Type | Default | Description |
|
|
162
|
+
| ------------ | --------- | ----------- | ------------------------------------------ |
|
|
163
|
+
| `filePath` | `string` | — | Path to the `.enc` file |
|
|
164
|
+
| `password` | `string` | — | Password used during encryption |
|
|
165
|
+
| `outputPath` | `string` | `undefined` | Optional path to write decrypted output to |
|
|
166
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
167
|
+
|
|
168
|
+
> The legacy 3-argument form `decryptFile(filePath, password, gzip)` is still fully supported, but will be deprecated in the next release.
|
|
169
|
+
|
|
170
|
+
**Returns:** `Buffer` when no `outputPath` is given, `undefined` otherwise.
|
|
171
|
+
|
|
172
|
+
**Throws:** `WilcoCryptError` with code `INVALID_FILE_EXTENSION` if `filePath` does not end in `.enc`.
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
// Return as Buffer
|
|
176
|
+
const buf = wilcocrypt.decryptFile("document.pdf.enc", "passw0rd");
|
|
177
|
+
|
|
178
|
+
// Write directly to disk
|
|
179
|
+
wilcocrypt.decryptFile("document.pdf.enc", "passw0rd", "document.pdf");
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### `encryptDataAsync(plaindata, password, gzip?)`
|
|
185
|
+
|
|
186
|
+
Asynchronous version of `encryptData`.
|
|
187
|
+
|
|
188
|
+
Encrypts a Buffer using password-based AES-256-GCM. The password is never stored; a random salt is generated for every encryption call.
|
|
189
|
+
|
|
190
|
+
| Parameter | Type | Default | Description |
|
|
191
|
+
| ----------- | --------- | ------- | ------------------------------------------ |
|
|
192
|
+
| `plaindata` | `Buffer` | — | Raw data to encrypt |
|
|
193
|
+
| `password` | `string` | — | Password for key derivation (min. 6 chars) |
|
|
194
|
+
| `gzip` | `boolean` | `true` | Compress data before encryption |
|
|
195
|
+
|
|
196
|
+
**Returns:** `Promise<Buffer>` — the encrypted payload in the binary format.
|
|
197
|
+
|
|
198
|
+
**Throws:** `WilcoCryptError` with code `WEAK_PASSWORD` if the password is too short.
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
const encrypted = await wilcocrypt.encryptDataAsync(
|
|
202
|
+
Buffer.from("secret"),
|
|
203
|
+
"passw0rd",
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### `decryptDataAsync(encryptedBuffer, password, gzip?)`
|
|
210
|
+
|
|
211
|
+
Asynchronous version of `decryptData`.
|
|
212
|
+
|
|
213
|
+
Decrypts a payload produced by `encryptDataAsync` or `encryptData`. Validates the header and version before attempting decryption.
|
|
214
|
+
|
|
215
|
+
| Parameter | Type | Default | Description |
|
|
216
|
+
| ----------------- | --------- | ------- | ------------------------------- |
|
|
217
|
+
| `encryptedBuffer` | `Buffer` | — | Payload from `encryptData` |
|
|
218
|
+
| `password` | `string` | — | Password used during encryption |
|
|
219
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
220
|
+
|
|
221
|
+
**Returns:** `Promise<Buffer>` — the original plaintext data.
|
|
222
|
+
|
|
223
|
+
**Throws:**
|
|
224
|
+
|
|
225
|
+
| Code | Reason |
|
|
226
|
+
| ------------------- | ---------------------------------------------- |
|
|
227
|
+
| `WEAK_PASSWORD` | Password shorter than 6 characters |
|
|
228
|
+
| `INVALID_HEADER` | Not a valid WilcoCrypt payload |
|
|
229
|
+
| `VERSION_MISMATCH` | Payload was encrypted with a different version |
|
|
230
|
+
| `DECRYPTION_FAILED` | Wrong password, tampered or corrupt data |
|
|
231
|
+
|
|
232
|
+
```js
|
|
233
|
+
const plain = await wilcocrypt.decryptDataAsync(
|
|
234
|
+
encrypted,
|
|
235
|
+
"passw0rd",
|
|
236
|
+
);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### `encryptFileAsync(filePath, password, gzip?)`
|
|
242
|
+
|
|
243
|
+
Asynchronous version of `encryptFile`.
|
|
244
|
+
|
|
245
|
+
Reads a file, encrypts it, and writes the result to `<filePath>.enc`.
|
|
246
|
+
|
|
247
|
+
| Parameter | Type | Default | Description |
|
|
248
|
+
| ---------- | --------- | ------- | --------------------------- |
|
|
249
|
+
| `filePath` | `string` | — | Path to the source file |
|
|
250
|
+
| `password` | `string` | — | Password for key derivation |
|
|
251
|
+
| `gzip` | `boolean` | `true` | Compress before encryption |
|
|
252
|
+
|
|
253
|
+
**Returns:** `Promise<void>`
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
await wilcocrypt.encryptFileAsync(
|
|
257
|
+
"document.pdf",
|
|
258
|
+
"passw0rd",
|
|
259
|
+
);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### `decryptFileAsync(filePath, password, outputPath?, gzip?)`
|
|
265
|
+
|
|
266
|
+
Asynchronous version of `decryptFile`.
|
|
267
|
+
|
|
268
|
+
If `outputPath` is provided, the result is written to disk and `undefined` is returned. Otherwise the decrypted `Buffer` is returned.
|
|
269
|
+
|
|
270
|
+
| Parameter | Type | Default | Description |
|
|
271
|
+
| ------------ | --------- | ----------- | ------------------------------------------ |
|
|
272
|
+
| `filePath` | `string` | — | Path to the `.enc` file |
|
|
273
|
+
| `password` | `string` | — | Password used during encryption |
|
|
274
|
+
| `outputPath` | `string` | `undefined` | Optional path to write decrypted output to |
|
|
275
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
276
|
+
|
|
277
|
+
**Returns:** `Promise<Buffer>` when no `outputPath` is given, `Promise<undefined>` otherwise.
|
|
278
|
+
|
|
279
|
+
**Throws:** Same error codes as `decryptFile`.
|
|
280
|
+
|
|
281
|
+
```js
|
|
282
|
+
// Return as Buffer
|
|
283
|
+
const buf = await wilcocrypt.decryptFileAsync(
|
|
284
|
+
"document.pdf.enc",
|
|
285
|
+
"passw0rd",
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// Write directly to disk
|
|
289
|
+
await wilcocrypt.decryptFileAsync(
|
|
290
|
+
"document.pdf.enc",
|
|
291
|
+
"passw0rd",
|
|
292
|
+
"document.pdf",
|
|
293
|
+
);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### `encryptFileStream(inputPath, outputPath, password, gzip?)`
|
|
299
|
+
|
|
300
|
+
Streaming equivalent of `encryptFile`. Reads from `inputPath` and writes to `outputPath` chunk by chunk — suitable for large files where loading everything into memory is impractical.
|
|
301
|
+
|
|
302
|
+
| Parameter | Type | Default | Description |
|
|
303
|
+
| ------------ | --------- | ------- | ----------------------------- |
|
|
304
|
+
| `inputPath` | `string` | — | Path to the source file |
|
|
305
|
+
| `outputPath` | `string` | — | Path for the encrypted output |
|
|
306
|
+
| `password` | `string` | — | Password for key derivation |
|
|
307
|
+
| `gzip` | `boolean` | `true` | Compress before encryption |
|
|
308
|
+
|
|
309
|
+
**Returns:** `Promise<void>`
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
await wilcocrypt.encryptFileStream(
|
|
313
|
+
"bigfile.zip",
|
|
314
|
+
"bigfile.zip.enc",
|
|
315
|
+
"passw0rd",
|
|
316
|
+
);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
### `decryptFileStream(inputPath, outputPath, password, gzip?)`
|
|
322
|
+
|
|
323
|
+
Streaming equivalent of `decryptFile`. Header and version are validated before the stream starts. If decryption fails at any point, the partially written output file is deleted automatically.
|
|
324
|
+
|
|
325
|
+
| Parameter | Type | Default | Description |
|
|
326
|
+
| ------------ | --------- | ------- | --------------------------------- |
|
|
327
|
+
| `inputPath` | `string` | — | Path to the `.enc` file |
|
|
328
|
+
| `outputPath` | `string` | — | Path to write decrypted output to |
|
|
329
|
+
| `password` | `string` | — | Password used during encryption |
|
|
330
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
331
|
+
|
|
332
|
+
**Returns:** `Promise<void>`
|
|
333
|
+
|
|
334
|
+
**Throws:** Same error codes as `decryptData`, plus automatic cleanup of `outputPath` on failure.
|
|
335
|
+
|
|
336
|
+
```js
|
|
337
|
+
await wilcocrypt.decryptFileStream(
|
|
338
|
+
"bigfile.zip.enc",
|
|
339
|
+
"bigfile.zip",
|
|
340
|
+
"passw0rd",
|
|
341
|
+
);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
### Internal Namespace (`_`)
|
|
347
|
+
|
|
348
|
+
The `wilcocrypt._` namespace exposes internal helpers. These are not intended for normal use but are part of the public surface for advanced use cases and testing.
|
|
349
|
+
|
|
350
|
+
| Member | Type | Description |
|
|
351
|
+
| ----------------------------------------------------- | ---------- | ------------------------------------------------------------- |
|
|
352
|
+
| `_.VERSION` | `string` | Current version string, embedded in every payload |
|
|
353
|
+
| `_.MIN_PASSWORD_LENGTH` | `number` | Minimum accepted password length (6) |
|
|
354
|
+
| `_.HEADER` | `Buffer` | 10-byte magic bytes identifying a WilcoCrypt payload |
|
|
355
|
+
| `_.WilcoCryptError` | `class` | The error class (also importable from TypeScript types) |
|
|
356
|
+
| `_.assertKeyAndIv(key, iv)` | `function` | Throws if key or IV are not valid Buffers of the right length |
|
|
357
|
+
| `_.assertPassword(password)` | `function` | Throws `WEAK_PASSWORD` if password is too short |
|
|
358
|
+
| `_.constantTimeEqual(a, b)` | `function` | Constant-time Buffer comparison, returns `boolean` |
|
|
359
|
+
| `_.encryptData(plainData, key, iv)` | `function` | Raw AES-256-GCM encryption, returns `{ ciphertext, authTag }` |
|
|
360
|
+
| `_.decryptData(cipherBuffer, authTagBuffer, key, iv)` | `function` | Raw AES-256-GCM decryption, returns `Buffer` |
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## CLI Reference
|
|
365
|
+
|
|
366
|
+
Install globally or use via `npx`:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
npm install -g wilcocrypt
|
|
370
|
+
wilcocrypt --help
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Options
|
|
374
|
+
|
|
375
|
+
| Flag | Description |
|
|
376
|
+
| ---------------------- | ----------------------------------------------------- |
|
|
377
|
+
| `-e, --encrypt <file>` | Encrypt the given file, writes `<file>.enc` |
|
|
378
|
+
| `-d, --decrypt <file>` | Decrypt the given `.enc` file |
|
|
379
|
+
| `-o, --output <file>` | Write decrypted output to `<file>` instead of stdout |
|
|
380
|
+
| `--stdout` | Explicitly write decrypted output to stdout (default) |
|
|
381
|
+
| `--version` | Show WilcoCrypt version |
|
|
382
|
+
| `-h, --help` | Show help |
|
|
383
|
+
|
|
384
|
+
Only one of `-e` or `-d` may be used at a time. The `--output` and `--stdout` flags are mutually exclusive. `--output` is only valid with `-d`.
|
|
385
|
+
|
|
386
|
+
### Examples
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
# Encrypt a file
|
|
390
|
+
wilcocrypt -e secret.txt
|
|
391
|
+
# → prompts for password, writes secret.txt.enc
|
|
392
|
+
|
|
393
|
+
# Decrypt to stdout (pipe-friendly)
|
|
394
|
+
wilcocrypt -d secret.txt.enc
|
|
395
|
+
# → prompts for password, writes to stdout
|
|
396
|
+
|
|
397
|
+
# Decrypt to a file
|
|
398
|
+
wilcocrypt -d secret.txt.enc -o secret.txt
|
|
399
|
+
# → prompts for password, writes to secret.txt
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Passwords are entered interactively with character masking (`*`). The CLI requires a TTY; piping passwords in is intentionally not supported.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Binary Payload Format
|
|
407
|
+
|
|
408
|
+
Every payload produced in WilcoCrypt v2.2.x has the following binary layout:
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
[ HEADER ] 10 bytes — magic bytes: 23 9 12 3 15 3 18 25 16 20
|
|
412
|
+
[ VERSION ] dynamic — UTF-8 version string (e.g. "2.2.0"), 5 bytes for current version
|
|
413
|
+
[ salt ] 16 bytes — random salt for scrypt key derivation
|
|
414
|
+
[ iv ] 12 bytes — random IV for AES-256-GCM
|
|
415
|
+
[ ciphertext] variable — AES-256-GCM encrypted (and optionally gzip-compressed) data
|
|
416
|
+
[ authTag ] 16 bytes — GCM authentication tag
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
The auth tag is placed at the end to allow the streaming API to append it after the pipeline finishes, without needing to seek backwards in the output stream.
|
|
420
|
+
|
|
421
|
+
> **Compatibility note:** The format changed between v2.1.x and v2.2.0. Files encrypted with v2.1.x cannot be decrypted with v2.2.0 and will throw a `VERSION_MISMATCH` or `INVALID_HEADER` error.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Error Handling
|
|
426
|
+
|
|
427
|
+
All errors thrown by WilcoCrypt are instances of `WilcoCryptError`, which extends `Error` with a `code` property.
|
|
428
|
+
|
|
429
|
+
```js
|
|
430
|
+
import wilcocrypt from "wilcocrypt";
|
|
431
|
+
const { WilcoCryptError } = wilcocrypt._;
|
|
432
|
+
|
|
433
|
+
try {
|
|
434
|
+
wilcocrypt.decryptData(payload, "wrong-password");
|
|
435
|
+
} catch (err) {
|
|
436
|
+
if (err instanceof WilcoCryptError) {
|
|
437
|
+
console.error(err.code); // e.g. DECRYPTION_FAILED
|
|
438
|
+
console.error(err.message); // human-readable
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Error Codes
|
|
444
|
+
|
|
445
|
+
| Code | Thrown by | Cause |
|
|
446
|
+
| ------------------------ | --------------------------------------------- | ------------------------------------------------------ |
|
|
447
|
+
| `WEAK_PASSWORD` | All public methods | Password shorter than 6 characters |
|
|
448
|
+
| `INVALID_HEADER` | `decryptData`, `decryptFile`, stream variants | Payload does not start with the WilcoCrypt magic bytes |
|
|
449
|
+
| `VERSION_MISMATCH` | `decryptData`, `decryptFile`, stream variants | Payload version does not match current version |
|
|
450
|
+
| `DECRYPTION_FAILED` | `decryptData`, `decryptFile`, stream variants | Wrong password, tampered data, or corruption |
|
|
451
|
+
| `INVALID_FILE_EXTENSION` | `decryptFile` | File path does not end with `.enc` |
|
|
452
|
+
| `INVALID_KEY` | `_.assertKeyAndIv` | Key is not a 32-byte Buffer |
|
|
453
|
+
| `INVALID_IV` | `_.assertKeyAndIv` | IV is not a 12-byte Buffer |
|
|
454
|
+
| `NO_TTY` | CLI password prompt | stdin is not a TTY |
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## TypeScript
|
|
459
|
+
|
|
460
|
+
WilcoCrypt ships with `wilcocrypt.d.ts`. No `@types` package needed.
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
import wilcocrypt, {
|
|
464
|
+
WilcoCryptError,
|
|
465
|
+
} from "wilcocrypt";
|
|
466
|
+
|
|
467
|
+
const encrypted: Buffer =
|
|
468
|
+
wilcocrypt.encryptData(
|
|
469
|
+
Buffer.from("hi"),
|
|
470
|
+
"passw0rd",
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
const encryptedAsync: Buffer =
|
|
474
|
+
await wilcocrypt.encryptDataAsync(
|
|
475
|
+
Buffer.from("hi"),
|
|
476
|
+
"passw0rd",
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
// decryptFile overloads
|
|
480
|
+
const buf: Buffer =
|
|
481
|
+
wilcocrypt.decryptFile(
|
|
482
|
+
"file.enc",
|
|
483
|
+
"passw0rd",
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
wilcocrypt.decryptFile(
|
|
487
|
+
"file.enc",
|
|
488
|
+
"passw0rd",
|
|
489
|
+
"output.txt",
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
// async overloads
|
|
493
|
+
const asyncBuf: Buffer =
|
|
494
|
+
await wilcocrypt.decryptFileAsync(
|
|
495
|
+
"file.enc",
|
|
496
|
+
"passw0rd",
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
await wilcocrypt.decryptFileAsync(
|
|
500
|
+
"file.enc",
|
|
501
|
+
"passw0rd",
|
|
502
|
+
"output.txt",
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
// streams
|
|
506
|
+
await wilcocrypt.encryptFileStream(
|
|
507
|
+
"in.txt",
|
|
508
|
+
"in.txt.enc",
|
|
509
|
+
"passw0rd",
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
await wilcocrypt.decryptFileStream(
|
|
513
|
+
"in.txt.enc",
|
|
514
|
+
"out.txt",
|
|
515
|
+
"passw0rd",
|
|
516
|
+
);
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## Security Notes
|
|
522
|
+
|
|
523
|
+
- **Key derivation** uses [scrypt](https://nodejs.org/api/crypto.html#cryptoscryptsyncpassword-salt-keylen-options) with a 16-byte random salt generated fresh for every encryption. The same password will produce a different key each time.
|
|
524
|
+
- **Authenticated encryption** via AES-256-GCM means any tampering with the ciphertext or auth tag will cause decryption to fail with `DECRYPTION_FAILED`.
|
|
525
|
+
- **No password is stored** anywhere in the payload. There is no way to recover a lost password.
|
|
526
|
+
- **The `gzip` flag must match** between encryption and decryption. If data was encrypted without compression (`gzip: false`), decryption must also use `gzip: false`.
|
|
527
|
+
- See [SECURITY.md](./SECURITY.md) for the responsible disclosure policy.
|