wilcocrypt 2.1.1 → 2.2.0
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 +78 -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 +62 -0
- package/DOCS.md +335 -0
- package/README.md +59 -64
- package/SECURITY.md +48 -0
- package/package.json +9 -6
- package/src/cli.js +26 -9
- package/src/wilcocrypt.js +205 -85
- package/types/wilcocrypt.d.ts +127 -13
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
about: Report a bug or unexpected behavior in WilcoCrypt
|
|
3
|
+
title: "[BUG] "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
|
|
6
|
+
body:
|
|
7
|
+
- type: markdown
|
|
8
|
+
attributes:
|
|
9
|
+
value: "## Bug report"
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: description
|
|
13
|
+
attributes:
|
|
14
|
+
label: Description
|
|
15
|
+
description: Describe what went wrong
|
|
16
|
+
placeholder: Clearly explain the issue
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: steps
|
|
22
|
+
attributes:
|
|
23
|
+
label: Steps to reproduce
|
|
24
|
+
description: How can this issue be reproduced?
|
|
25
|
+
value: |
|
|
26
|
+
1.
|
|
27
|
+
2.
|
|
28
|
+
3.
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: expected
|
|
34
|
+
attributes:
|
|
35
|
+
label: Expected behavior
|
|
36
|
+
description: What did you expect to happen?
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
|
|
40
|
+
- type: textarea
|
|
41
|
+
id: actual
|
|
42
|
+
attributes:
|
|
43
|
+
label: Actual behavior
|
|
44
|
+
description: What actually happened?
|
|
45
|
+
validations:
|
|
46
|
+
required: true
|
|
47
|
+
|
|
48
|
+
- type: input
|
|
49
|
+
id: version
|
|
50
|
+
attributes:
|
|
51
|
+
label: WilcoCrypt version
|
|
52
|
+
placeholder: e.g. 2.1.1
|
|
53
|
+
validations:
|
|
54
|
+
required: true
|
|
55
|
+
|
|
56
|
+
- type: input
|
|
57
|
+
id: node
|
|
58
|
+
attributes:
|
|
59
|
+
label: Node.js version
|
|
60
|
+
placeholder: e.g. 22.x
|
|
61
|
+
|
|
62
|
+
- type: dropdown
|
|
63
|
+
id: environment
|
|
64
|
+
attributes:
|
|
65
|
+
label: Environment
|
|
66
|
+
options:
|
|
67
|
+
- Linux
|
|
68
|
+
- Windows
|
|
69
|
+
- macOS
|
|
70
|
+
- Other
|
|
71
|
+
validations:
|
|
72
|
+
required: true
|
|
73
|
+
|
|
74
|
+
- type: textarea
|
|
75
|
+
id: additional
|
|
76
|
+
attributes:
|
|
77
|
+
label: Additional context
|
|
78
|
+
description: Logs, errors, or anything else
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
about: Suggest an idea or improvement for WilcoCrypt
|
|
3
|
+
title: "[FEATURE] "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
|
|
6
|
+
body:
|
|
7
|
+
- type: markdown
|
|
8
|
+
attributes:
|
|
9
|
+
value: "## Feature request"
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem
|
|
15
|
+
description: What problem does this solve?
|
|
16
|
+
placeholder: Describe the issue you're facing
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: solution
|
|
22
|
+
attributes:
|
|
23
|
+
label: Proposed solution
|
|
24
|
+
description: What would you like to see?
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: alternatives
|
|
30
|
+
attributes:
|
|
31
|
+
label: Alternatives considered
|
|
32
|
+
description: Any alternative solutions you've thought about?
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: context
|
|
36
|
+
attributes:
|
|
37
|
+
label: Additional context
|
|
38
|
+
description: Extra details, use cases, or examples
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to WilcoCrypt are documented here.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## [2.2.0] - 2026-05-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Streaming API** — `encryptFileStream(inputPath, outputPath, password, gzip?)` and `decryptFileStream(inputPath, outputPath, password, gzip?)` for memory-efficient encryption and decryption of large files using Node.js streams.
|
|
12
|
+
- **`decryptFile` output path** — `decryptFile` now accepts an optional `outputPath` argument. When provided, decrypted data is written directly to that file instead of being returned as a Buffer. Fully backward compatible.
|
|
13
|
+
- Internal `HEADER` constant (`[23, 9, 12, 3, 15, 3, 18, 25, 16, 20]`) for payload identification.
|
|
14
|
+
- **CLI `-o` / `--output` flag** — Decrypted output can now be written to a file via `-o <file>` instead of always piping to stdout.
|
|
15
|
+
- **CLI `--stdout` flag** — Explicit flag to write decrypted output to stdout (this remains the default when `-o` is omitted).
|
|
16
|
+
- **Version check on decryption** — The version string is now embedded in the encrypted payload and validated during decryption. Payloads from a different version are rejected with a `VERSION_MISMATCH` error.
|
|
17
|
+
- **GitHub issue templates** (bug report, feature request) and `issue_config.yml`.
|
|
18
|
+
- **`dependabot.yml`** for automated dependency updates.
|
|
19
|
+
- **`SECURITY.md`** with responsible disclosure policy.
|
|
20
|
+
- **`DOCS.md`** — full API reference, CLI docs, payload format, TypeScript usage, and security notes.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **Binary payload format** — The encrypted payload format has been updated. The version string is now included between the header and salt, and the auth tag has moved to the **end** of the payload (after the ciphertext) to support streaming. The new layout is:
|
|
25
|
+
`[HEADER (10)] + [VERSION (dynamic)] + [salt (16)] + [iv (12)] + [ciphertext] + [authTag (16)]`
|
|
26
|
+
> Payloads encrypted with v2.1.1 are not compatible with v2.2.0 and vice versa.
|
|
27
|
+
- **Removed `notepack.io`** — The MessagePack dependency has been dropped entirely. The custom binary format replaces the previous envelope-based approach.
|
|
28
|
+
- **VERSION** bumped from `2.1.1` to `2.2.0`.
|
|
29
|
+
- **Linting** — Codebase now enforces [semistandard](https://github.com/standard/semistandard) style (Standard JS + semicolons).
|
|
30
|
+
- **TypeScript types** updated with overloads for the new `decryptFile` signature and the two new stream methods.
|
|
31
|
+
- **README** updated with stability warning, new features, and links to `DOCS.md` and `CHANGELOG.md`.
|
|
32
|
+
|
|
33
|
+
### Internal
|
|
34
|
+
|
|
35
|
+
- Stream decryption performs early header and version validation before opening the output stream, and automatically cleans up the output file on failure.
|
|
36
|
+
- `_.decryptData` internal helper now accepts raw `Buffer` arguments (previously hex strings).
|
|
37
|
+
|
|
38
|
+
### Fixed Bugs
|
|
39
|
+
|
|
40
|
+
- Fixed the bug where the CLI tool would not work when running with npx or global
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [2.1.1] - 2026-04-26
|
|
45
|
+
|
|
46
|
+
First official GitHub release of WilcoCrypt.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- Full TypeScript support (`wilcocrypt.d.ts`).
|
|
51
|
+
- Pre-built binaries for Linux x64/arm64, macOS x64/arm64, and Windows x64.
|
|
52
|
+
- `WilcoCryptError` custom error class with machine-readable `code` property.
|
|
53
|
+
- Internal helpers: `assertKeyAndIv`, `assertPassword`, `constantTimeEqual`.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Removed Rollup bundle from the npm package (Rollup is still used for building binaries).
|
|
58
|
+
- README improvements and consistency fixes.
|
|
59
|
+
|
|
60
|
+
### Notes
|
|
61
|
+
|
|
62
|
+
- The CLI `wilcocrypt` command does not work when installed globally via npm in this release. Use the provided binaries as a workaround. This is fixed in v2.2.0.
|
package/DOCS.md
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
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
|
+
- [encryptFileStream](#encryptfilestream)
|
|
17
|
+
- [decryptFileStream](#decryptfilestream)
|
|
18
|
+
- [Internal Namespace (`_`)](#internal-namespace-_)
|
|
19
|
+
- [CLI Reference](#cli-reference)
|
|
20
|
+
- [Binary Payload Format](#binary-payload-format)
|
|
21
|
+
- [Error Handling](#error-handling)
|
|
22
|
+
- [TypeScript](#typescript)
|
|
23
|
+
- [Security Notes](#security-notes)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install wilcocrypt
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Requires Node.js 18 or later (uses `stream/promises` and `fs/promises`).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import wilcocrypt from 'wilcocrypt';
|
|
41
|
+
|
|
42
|
+
// Encrypt a Buffer
|
|
43
|
+
const data = Buffer.from('Hello, world!');
|
|
44
|
+
const encrypted = wilcocrypt.encryptData(data, 'my-password');
|
|
45
|
+
|
|
46
|
+
// Decrypt it back
|
|
47
|
+
const decrypted = wilcocrypt.decryptData(encrypted, 'my-password');
|
|
48
|
+
console.log(decrypted.toString()); // Hello, world!
|
|
49
|
+
|
|
50
|
+
// Encrypt a file (writes file.txt.enc)
|
|
51
|
+
wilcocrypt.encryptFile('file.txt', 'my-password');
|
|
52
|
+
|
|
53
|
+
// Decrypt a file (returns Buffer)
|
|
54
|
+
const contents = wilcocrypt.decryptFile('file.txt.enc', 'my-password');
|
|
55
|
+
|
|
56
|
+
// Decrypt a file directly to disk
|
|
57
|
+
wilcocrypt.decryptFile('file.txt.enc', 'my-password', 'output.txt');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
### `encryptData(plaindata, password, gzip?)`
|
|
65
|
+
|
|
66
|
+
Encrypts a Buffer using password-based AES-256-GCM. The password is never stored; a random salt is generated for every encryption call.
|
|
67
|
+
|
|
68
|
+
| Parameter | Type | Default | Description |
|
|
69
|
+
|------------|-----------|---------|--------------------------------------|
|
|
70
|
+
| `plaindata`| `Buffer` | — | Raw data to encrypt |
|
|
71
|
+
| `password` | `string` | — | Password for key derivation (min. 6 chars) |
|
|
72
|
+
| `gzip` | `boolean` | `true` | Compress data before encryption |
|
|
73
|
+
|
|
74
|
+
**Returns:** `Buffer` — the encrypted payload in the [binary format](#binary-payload-format).
|
|
75
|
+
|
|
76
|
+
**Throws:** `WilcoCryptError` with code `WEAK_PASSWORD` if the password is too short.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const encrypted = wilcocrypt.encryptData(Buffer.from('secret'), 'passw0rd');
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### `decryptData(encryptedBuffer, password, gzip?)`
|
|
85
|
+
|
|
86
|
+
Decrypts a payload produced by `encryptData`. Validates the header and version before attempting decryption.
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Default | Description |
|
|
89
|
+
|-------------------|-----------|---------|-------------------------------------|
|
|
90
|
+
| `encryptedBuffer` | `Buffer` | — | Payload from `encryptData` |
|
|
91
|
+
| `password` | `string` | — | Password used during encryption |
|
|
92
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
93
|
+
|
|
94
|
+
**Returns:** `Buffer` — the original plaintext data.
|
|
95
|
+
|
|
96
|
+
**Throws:**
|
|
97
|
+
|
|
98
|
+
| Code | Reason |
|
|
99
|
+
|---------------------|-------------------------------------------|
|
|
100
|
+
| `WEAK_PASSWORD` | Password shorter than 6 characters |
|
|
101
|
+
| `INVALID_HEADER` | Not a valid WilcoCrypt payload |
|
|
102
|
+
| `VERSION_MISMATCH` | Payload was encrypted with a different version |
|
|
103
|
+
| `DECRYPTION_FAILED` | Wrong password, tampered or corrupt data |
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const plain = wilcocrypt.decryptData(encrypted, 'passw0rd');
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### `encryptFile(filePath, password, gzip?)`
|
|
112
|
+
|
|
113
|
+
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.
|
|
114
|
+
|
|
115
|
+
| Parameter | Type | Default | Description |
|
|
116
|
+
|------------|-----------|---------|---------------------------------|
|
|
117
|
+
| `filePath` | `string` | — | Path to the source file |
|
|
118
|
+
| `password` | `string` | — | Password for key derivation |
|
|
119
|
+
| `gzip` | `boolean` | `true` | Compress before encryption |
|
|
120
|
+
|
|
121
|
+
**Returns:** `void`
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
wilcocrypt.encryptFile('document.pdf', 'passw0rd');
|
|
125
|
+
// Creates document.pdf.enc
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### `decryptFile(filePath, password, outputPath?, gzip?)`
|
|
131
|
+
|
|
132
|
+
Decrypts a `.enc` file. If `outputPath` is provided, the result is written to disk and `undefined` is returned. Otherwise the decrypted `Buffer` is returned.
|
|
133
|
+
|
|
134
|
+
| Parameter | Type | Default | Description |
|
|
135
|
+
|--------------|-----------|-------------|-------------------------------------------------------|
|
|
136
|
+
| `filePath` | `string` | — | Path to the `.enc` file |
|
|
137
|
+
| `password` | `string` | — | Password used during encryption |
|
|
138
|
+
| `outputPath` | `string` | `undefined` | Optional path to write decrypted output to |
|
|
139
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
140
|
+
|
|
141
|
+
> The legacy 3-argument form `decryptFile(filePath, password, gzip)` is still fully supported, but will be deprecated in the next release.
|
|
142
|
+
|
|
143
|
+
**Returns:** `Buffer` when no `outputPath` is given, `undefined` otherwise.
|
|
144
|
+
|
|
145
|
+
**Throws:** `WilcoCryptError` with code `INVALID_FILE_EXTENSION` if `filePath` does not end in `.enc`.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// Return as Buffer
|
|
149
|
+
const buf = wilcocrypt.decryptFile('document.pdf.enc', 'passw0rd');
|
|
150
|
+
|
|
151
|
+
// Write directly to disk
|
|
152
|
+
wilcocrypt.decryptFile('document.pdf.enc', 'passw0rd', 'document.pdf');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### `encryptFileStream(inputPath, outputPath, password, gzip?)`
|
|
158
|
+
|
|
159
|
+
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.
|
|
160
|
+
|
|
161
|
+
| Parameter | Type | Default | Description |
|
|
162
|
+
|--------------|-----------|---------|--------------------------------------|
|
|
163
|
+
| `inputPath` | `string` | — | Path to the source file |
|
|
164
|
+
| `outputPath` | `string` | — | Path for the encrypted output |
|
|
165
|
+
| `password` | `string` | — | Password for key derivation |
|
|
166
|
+
| `gzip` | `boolean` | `true` | Compress before encryption |
|
|
167
|
+
|
|
168
|
+
**Returns:** `Promise<void>`
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
await wilcocrypt.encryptFileStream('bigfile.zip', 'bigfile.zip.enc', 'passw0rd');
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### `decryptFileStream(inputPath, outputPath, password, gzip?)`
|
|
177
|
+
|
|
178
|
+
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.
|
|
179
|
+
|
|
180
|
+
| Parameter | Type | Default | Description |
|
|
181
|
+
|--------------|-----------|---------|---------------------------------------|
|
|
182
|
+
| `inputPath` | `string` | — | Path to the `.enc` file |
|
|
183
|
+
| `outputPath` | `string` | — | Path to write decrypted output to |
|
|
184
|
+
| `password` | `string` | — | Password used during encryption |
|
|
185
|
+
| `gzip` | `boolean` | `true` | Decompress after decryption |
|
|
186
|
+
|
|
187
|
+
**Returns:** `Promise<void>`
|
|
188
|
+
|
|
189
|
+
**Throws:** Same error codes as `decryptData`, plus automatic cleanup of `outputPath` on failure.
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
await wilcocrypt.decryptFileStream('bigfile.zip.enc', 'bigfile.zip', 'passw0rd');
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### Internal Namespace (`_`)
|
|
198
|
+
|
|
199
|
+
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.
|
|
200
|
+
|
|
201
|
+
| Member | Type | Description |
|
|
202
|
+
|-------------------------|------------|----------------------------------------------------------|
|
|
203
|
+
| `_.VERSION` | `string` | Current version string, embedded in every payload |
|
|
204
|
+
| `_.MIN_PASSWORD_LENGTH` | `number` | Minimum accepted password length (6) |
|
|
205
|
+
| `_.HEADER` | `Buffer` | 10-byte magic bytes identifying a WilcoCrypt payload |
|
|
206
|
+
| `_.WilcoCryptError` | `class` | The error class (also importable from TypeScript types) |
|
|
207
|
+
| `_.assertKeyAndIv(key, iv)` | `function` | Throws if key or IV are not valid Buffers of the right length |
|
|
208
|
+
| `_.assertPassword(password)` | `function` | Throws `WEAK_PASSWORD` if password is too short |
|
|
209
|
+
| `_.constantTimeEqual(a, b)` | `function` | Constant-time Buffer comparison, returns `boolean` |
|
|
210
|
+
| `_.encryptData(plainData, key, iv)` | `function` | Raw AES-256-GCM encryption, returns `{ ciphertext, authTag }` |
|
|
211
|
+
| `_.decryptData(cipherBuffer, authTagBuffer, key, iv)` | `function` | Raw AES-256-GCM decryption, returns `Buffer` |
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## CLI Reference
|
|
216
|
+
|
|
217
|
+
Install globally or use via `npx`:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm install -g wilcocrypt
|
|
221
|
+
wilcocrypt --help
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Options
|
|
225
|
+
|
|
226
|
+
| Flag | Description |
|
|
227
|
+
|--------------------------|-----------------------------------------------------|
|
|
228
|
+
| `-e, --encrypt <file>` | Encrypt the given file, writes `<file>.enc` |
|
|
229
|
+
| `-d, --decrypt <file>` | Decrypt the given `.enc` file |
|
|
230
|
+
| `-o, --output <file>` | Write decrypted output to `<file>` instead of stdout |
|
|
231
|
+
| `--stdout` | Explicitly write decrypted output to stdout (default) |
|
|
232
|
+
| `--version` | Show WilcoCrypt version |
|
|
233
|
+
| `-h, --help` | Show help |
|
|
234
|
+
|
|
235
|
+
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`.
|
|
236
|
+
|
|
237
|
+
### Examples
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Encrypt a file
|
|
241
|
+
wilcocrypt -e secret.txt
|
|
242
|
+
# → prompts for password, writes secret.txt.enc
|
|
243
|
+
|
|
244
|
+
# Decrypt to stdout (pipe-friendly)
|
|
245
|
+
wilcocrypt -d secret.txt.enc
|
|
246
|
+
# → prompts for password, writes to stdout
|
|
247
|
+
|
|
248
|
+
# Decrypt to a file
|
|
249
|
+
wilcocrypt -d secret.txt.enc -o secret.txt
|
|
250
|
+
# → prompts for password, writes to secret.txt
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Passwords are entered interactively with character masking (`*`). The CLI requires a TTY; piping passwords in is intentionally not supported.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Binary Payload Format
|
|
258
|
+
|
|
259
|
+
Every payload produced by WilcoCrypt v2.2.0 has the following binary layout:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
[ HEADER ] 10 bytes — magic bytes: 23 9 12 3 15 3 18 25 16 20
|
|
263
|
+
[ VERSION ] dynamic — UTF-8 version string (e.g. "2.2.0"), 5 bytes for current version
|
|
264
|
+
[ salt ] 16 bytes — random salt for scrypt key derivation
|
|
265
|
+
[ iv ] 12 bytes — random IV for AES-256-GCM
|
|
266
|
+
[ ciphertext] variable — AES-256-GCM encrypted (and optionally gzip-compressed) data
|
|
267
|
+
[ authTag ] 16 bytes — GCM authentication tag
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
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.
|
|
271
|
+
|
|
272
|
+
> **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.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Error Handling
|
|
277
|
+
|
|
278
|
+
All errors thrown by WilcoCrypt are instances of `WilcoCryptError`, which extends `Error` with a `code` property.
|
|
279
|
+
|
|
280
|
+
```js
|
|
281
|
+
import wilcocrypt from 'wilcocrypt';
|
|
282
|
+
const { WilcoCryptError } = wilcocrypt._;
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
wilcocrypt.decryptData(payload, 'wrong-password');
|
|
286
|
+
} catch (err) {
|
|
287
|
+
if (err instanceof WilcoCryptError) {
|
|
288
|
+
console.error(err.code); // e.g. DECRYPTION_FAILED
|
|
289
|
+
console.error(err.message); // human-readable
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Error Codes
|
|
295
|
+
|
|
296
|
+
| Code | Thrown by | Cause |
|
|
297
|
+
|-------------------------|----------------------------------|----------------------------------------------------|
|
|
298
|
+
| `WEAK_PASSWORD` | All public methods | Password shorter than 6 characters |
|
|
299
|
+
| `INVALID_HEADER` | `decryptData`, `decryptFile`, stream variants | Payload does not start with the WilcoCrypt magic bytes |
|
|
300
|
+
| `VERSION_MISMATCH` | `decryptData`, `decryptFile`, stream variants | Payload version does not match current version |
|
|
301
|
+
| `DECRYPTION_FAILED` | `decryptData`, `decryptFile`, stream variants | Wrong password, tampered data, or corruption |
|
|
302
|
+
| `INVALID_FILE_EXTENSION`| `decryptFile` | File path does not end with `.enc` |
|
|
303
|
+
| `INVALID_KEY` | `_.assertKeyAndIv` | Key is not a 32-byte Buffer |
|
|
304
|
+
| `INVALID_IV` | `_.assertKeyAndIv` | IV is not a 12-byte Buffer |
|
|
305
|
+
| `NO_TTY` | CLI password prompt | stdin is not a TTY |
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## TypeScript
|
|
310
|
+
|
|
311
|
+
WilcoCrypt ships with `wilcocrypt.d.ts`. No `@types` package needed.
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
import wilcocrypt, { WilcoCryptError } from 'wilcocrypt';
|
|
315
|
+
|
|
316
|
+
const encrypted: Buffer = wilcocrypt.encryptData(Buffer.from('hi'), 'passw0rd');
|
|
317
|
+
|
|
318
|
+
// decryptFile overloads
|
|
319
|
+
const buf: Buffer = wilcocrypt.decryptFile('file.enc', 'passw0rd');
|
|
320
|
+
wilcocrypt.decryptFile('file.enc', 'passw0rd', 'output.txt'); // returns undefined
|
|
321
|
+
|
|
322
|
+
// Streams
|
|
323
|
+
await wilcocrypt.encryptFileStream('in.txt', 'in.txt.enc', 'passw0rd');
|
|
324
|
+
await wilcocrypt.decryptFileStream('in.txt.enc', 'out.txt', 'passw0rd');
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Security Notes
|
|
330
|
+
|
|
331
|
+
- **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.
|
|
332
|
+
- **Authenticated encryption** via AES-256-GCM means any tampering with the ciphertext or auth tag will cause decryption to fail with `DECRYPTION_FAILED`.
|
|
333
|
+
- **No password is stored** anywhere in the payload. There is no way to recover a lost password.
|
|
334
|
+
- **The `gzip` flag must match** between encryption and decryption. If data was encrypted without compression (`gzip: false`), decryption must also use `gzip: false`.
|
|
335
|
+
- See [SECURITY.md](./SECURITY.md) for the responsible disclosure policy.
|