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
package/src/wilcocrypt.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes, scryptSync, createCipheriv, createDecipheriv } from 'crypto';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { gzipSync, gunzipSync, createGzip, createGunzip } from 'zlib';
|
|
3
|
+
import { readFileSync, writeFileSync, createReadStream, createWriteStream, promises as fsPromises } from 'fs';
|
|
4
|
+
import { pipeline } from 'stream/promises';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Main WilcoCrypt namespace.
|
|
@@ -25,7 +25,7 @@ class WilcoCryptError extends Error {
|
|
|
25
25
|
* @param {string} message - Human-readable error message
|
|
26
26
|
* @param {string} [code=WILCOCRYPT_ERROR] - Machine-readable error code
|
|
27
27
|
*/
|
|
28
|
-
constructor(message, code = 'WILCOCRYPT_ERROR') {
|
|
28
|
+
constructor (message, code = 'WILCOCRYPT_ERROR') {
|
|
29
29
|
super(message);
|
|
30
30
|
this.name = 'WilcoCryptError';
|
|
31
31
|
this.code = code;
|
|
@@ -47,7 +47,7 @@ wilcocrypt._.WilcoCryptError = WilcoCryptError;
|
|
|
47
47
|
* Must match exactly during decryption.
|
|
48
48
|
* @type {string}
|
|
49
49
|
*/
|
|
50
|
-
wilcocrypt._.VERSION = '2.
|
|
50
|
+
wilcocrypt._.VERSION = '2.2.0';
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Minimum allowed password length.
|
|
@@ -55,6 +55,12 @@ wilcocrypt._.VERSION = '2.1.1';
|
|
|
55
55
|
*/
|
|
56
56
|
wilcocrypt._.MIN_PASSWORD_LENGTH = 6;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Internal header for encrypted payloads.
|
|
60
|
+
* @type {Buffer}
|
|
61
|
+
*/
|
|
62
|
+
wilcocrypt._.HEADER = Buffer.from([23, 9, 12, 3, 15, 3, 18, 25, 16, 20]);
|
|
63
|
+
|
|
58
64
|
/* =========================
|
|
59
65
|
Internal helpers
|
|
60
66
|
========================= */
|
|
@@ -76,7 +82,7 @@ wilcocrypt._.assertKeyAndIv = function (key, iv) {
|
|
|
76
82
|
|
|
77
83
|
if (!Buffer.isBuffer(iv) || iv.length !== 12) {
|
|
78
84
|
throw new WilcoCryptError(
|
|
79
|
-
'Invalid IV (expected 12-byte Buffer
|
|
85
|
+
'Invalid IV (expected 12-byte Buffer)',
|
|
80
86
|
'INVALID_IV'
|
|
81
87
|
);
|
|
82
88
|
}
|
|
@@ -145,21 +151,21 @@ wilcocrypt._.encryptData = function (plainData, key, iv) {
|
|
|
145
151
|
/**
|
|
146
152
|
* Decrypts AES-256-GCM encrypted data.
|
|
147
153
|
*
|
|
148
|
-
* @param {
|
|
149
|
-
* @param {
|
|
154
|
+
* @param {Buffer} cipherBuffer
|
|
155
|
+
* @param {Buffer} authTagBuffer
|
|
150
156
|
* @param {Buffer} key
|
|
151
157
|
* @param {Buffer} iv
|
|
152
158
|
* @returns {Buffer}
|
|
153
159
|
*/
|
|
154
|
-
wilcocrypt._.decryptData = function (
|
|
160
|
+
wilcocrypt._.decryptData = function (cipherBuffer, authTagBuffer, key, iv) {
|
|
155
161
|
wilcocrypt._.assertKeyAndIv(key, iv);
|
|
156
162
|
|
|
157
163
|
try {
|
|
158
164
|
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
159
|
-
decipher.setAuthTag(
|
|
165
|
+
decipher.setAuthTag(authTagBuffer);
|
|
160
166
|
|
|
161
167
|
return Buffer.concat([
|
|
162
|
-
decipher.update(
|
|
168
|
+
decipher.update(cipherBuffer),
|
|
163
169
|
decipher.final()
|
|
164
170
|
]);
|
|
165
171
|
} catch {
|
|
@@ -177,90 +183,77 @@ wilcocrypt._.decryptData = function (cipherHex, authTagHex, key, iv) {
|
|
|
177
183
|
/**
|
|
178
184
|
* Encrypts data using password-based AES-256-GCM.
|
|
179
185
|
*
|
|
186
|
+
* Output format:
|
|
187
|
+
* [HEADER (10 bytes)] + [VERSION (dynamic)] + [salt (16)] + [iv (12)] + [ciphertext] + [authTag (16)]
|
|
188
|
+
*
|
|
180
189
|
* @param {Buffer} plaindata - Raw data to encrypt
|
|
181
190
|
* @param {string} password - Password used for key derivation
|
|
182
191
|
* @param {boolean} [gzip=true] - Whether to compress data before encryption
|
|
183
|
-
* @returns {Buffer}
|
|
192
|
+
* @returns {Buffer} Binary-encoded encrypted payload
|
|
184
193
|
* @throws {WilcoCryptError} If password is invalid
|
|
185
194
|
*/
|
|
186
195
|
wilcocrypt.encryptData = function (plaindata, password, gzip = true) {
|
|
187
|
-
|
|
196
|
+
wilcocrypt._.assertPassword(password);
|
|
188
197
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
} else {
|
|
193
|
-
gzipData = plaindata;
|
|
194
|
-
}
|
|
198
|
+
const gzipData = gzip ? gzipSync(plaindata) : plaindata;
|
|
199
|
+
const iv = randomBytes(12);
|
|
200
|
+
const salt = randomBytes(16);
|
|
195
201
|
|
|
196
|
-
|
|
197
|
-
const salt = randomBytes(16);
|
|
202
|
+
const key = scryptSync(password, salt, 32);
|
|
198
203
|
|
|
199
|
-
|
|
204
|
+
const { ciphertext, authTag } = wilcocrypt._.encryptData(gzipData, key, iv);
|
|
205
|
+
const versionBuf = Buffer.from(wilcocrypt._.VERSION);
|
|
200
206
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
return msgpack_encode(envelope);
|
|
207
|
+
return Buffer.concat([
|
|
208
|
+
wilcocrypt._.HEADER, // 10 bytes
|
|
209
|
+
versionBuf, // dynamic
|
|
210
|
+
salt, // 16 bytes
|
|
211
|
+
iv, // 12 bytes
|
|
212
|
+
ciphertext, // variable
|
|
213
|
+
authTag // 16 bytes (at the end for streaming compatibility)
|
|
214
|
+
]);
|
|
212
215
|
};
|
|
213
216
|
|
|
214
217
|
/**
|
|
215
218
|
* Decrypts encrypted data using password-based AES-256-GCM.
|
|
216
219
|
*
|
|
217
|
-
*
|
|
220
|
+
* Validates internal header and version, then extracts:
|
|
221
|
+
* salt, iv, authTag and ciphertext from the binary payload.
|
|
222
|
+
*
|
|
223
|
+
* @param {Buffer} encryptedBuffer - Binary-encoded encrypted payload
|
|
218
224
|
* @param {string} password - Password used for decryption
|
|
219
225
|
* @param {boolean} [gzip=true] - Whether to decompress after decryption
|
|
220
226
|
* @returns {Buffer} Decrypted raw data
|
|
221
|
-
* @throws {WilcoCryptError} On invalid
|
|
227
|
+
* @throws {WilcoCryptError} On invalid header, version mismatch, wrong password, or corrupted data
|
|
222
228
|
*/
|
|
223
|
-
wilcocrypt.decryptData = function (
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
let envelope;
|
|
227
|
-
try {
|
|
228
|
-
envelope = msgpack_decode(encryptedData);
|
|
229
|
-
} catch {
|
|
230
|
-
throw new WilcoCryptError(
|
|
231
|
-
'Invalid encrypted data format (not MessagePack)',
|
|
232
|
-
'INVALID_FORMAT'
|
|
233
|
-
);
|
|
234
|
-
}
|
|
229
|
+
wilcocrypt.decryptData = function (encryptedBuffer, password, gzip = true) {
|
|
230
|
+
wilcocrypt._.assertPassword(password);
|
|
235
231
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
`Version mismatch (expected ${wilcocrypt._.VERSION}, got ${envelope.version})`,
|
|
239
|
-
'VERSION_MISMATCH'
|
|
240
|
-
);
|
|
241
|
-
}
|
|
232
|
+
const versionBuf = Buffer.from(wilcocrypt._.VERSION);
|
|
233
|
+
let offset = 0;
|
|
242
234
|
|
|
243
|
-
|
|
235
|
+
const fileHeader = encryptedBuffer.subarray(offset, offset += wilcocrypt._.HEADER.length);
|
|
236
|
+
if (!fileHeader.equals(wilcocrypt._.HEADER)) {
|
|
237
|
+
throw new WilcoCryptError('Invalid WilcoCrypt header', 'INVALID_HEADER');
|
|
238
|
+
}
|
|
244
239
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
Buffer.from(envelope.iv, 'hex')
|
|
250
|
-
);
|
|
240
|
+
const fileVersion = encryptedBuffer.subarray(offset, offset += versionBuf.length);
|
|
241
|
+
if (!fileVersion.equals(versionBuf)) {
|
|
242
|
+
throw new WilcoCryptError('Version mismatch', 'VERSION_MISMATCH');
|
|
243
|
+
}
|
|
251
244
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
245
|
+
const salt = encryptedBuffer.subarray(offset, offset += 16);
|
|
246
|
+
const iv = encryptedBuffer.subarray(offset, offset += 12);
|
|
247
|
+
|
|
248
|
+
// authTag are the last 16 bytes; ciphertext is everything in between
|
|
249
|
+
const authTag = encryptedBuffer.subarray(encryptedBuffer.length - 16);
|
|
250
|
+
const ciphertext = encryptedBuffer.subarray(offset, encryptedBuffer.length - 16);
|
|
251
|
+
|
|
252
|
+
const key = scryptSync(password, salt, 32);
|
|
253
|
+
|
|
254
|
+
const decrypted = wilcocrypt._.decryptData(ciphertext, authTag, key, iv);
|
|
255
|
+
|
|
256
|
+
return gzip ? gunzipSync(decrypted) : decrypted;
|
|
264
257
|
};
|
|
265
258
|
|
|
266
259
|
/**
|
|
@@ -273,30 +266,157 @@ wilcocrypt.decryptData = function (encryptedData, password, gzip = true) {
|
|
|
273
266
|
* @throws {WilcoCryptError} If password is invalid
|
|
274
267
|
*/
|
|
275
268
|
wilcocrypt.encryptFile = function (filePath, password, gzip = true) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
269
|
+
const fileData = readFileSync(filePath);
|
|
270
|
+
const encryptedData = wilcocrypt.encryptData(fileData, password, gzip);
|
|
271
|
+
writeFileSync(`${filePath}.enc`, encryptedData);
|
|
279
272
|
};
|
|
280
273
|
|
|
281
274
|
/**
|
|
282
275
|
* Decrypts an encrypted `.enc` file.
|
|
283
276
|
*
|
|
277
|
+
* If `outputPath` is provided, the decrypted data is written to that file
|
|
278
|
+
* and `undefined` is returned. Otherwise the decrypted Buffer is returned.
|
|
279
|
+
*
|
|
284
280
|
* @param {string} filePath - Path to the `.enc` file
|
|
285
281
|
* @param {string} password - Password used for decryption
|
|
282
|
+
* @param {string|boolean} [outputPath] - Optional path to write decrypted output to.
|
|
283
|
+
* If omitted (or `true`/`false`), the function returns the decrypted Buffer instead.
|
|
286
284
|
* @param {boolean} [gzip=true] - Whether to decompress after decryption
|
|
287
|
-
* @returns {Buffer} Decrypted file contents
|
|
285
|
+
* @returns {Buffer|undefined} Decrypted file contents, or undefined if outputPath was given
|
|
288
286
|
* @throws {WilcoCryptError} If file extension is invalid or decryption fails
|
|
289
287
|
*/
|
|
290
|
-
wilcocrypt.decryptFile = function (filePath, password, gzip = true) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
288
|
+
wilcocrypt.decryptFile = function (filePath, password, outputPath, gzip = true) {
|
|
289
|
+
// Support legacy 3-argument form: decryptFile(filePath, password, gzip?)
|
|
290
|
+
if (typeof outputPath === 'boolean') {
|
|
291
|
+
gzip = outputPath;
|
|
292
|
+
outputPath = undefined;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!filePath.endsWith('.enc')) {
|
|
296
|
+
throw new WilcoCryptError(
|
|
297
|
+
'Invalid file extension (expected .enc)',
|
|
298
|
+
'INVALID_FILE_EXTENSION'
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const encryptedData = readFileSync(filePath);
|
|
303
|
+
const decrypted = wilcocrypt.decryptData(encryptedData, password, gzip);
|
|
304
|
+
|
|
305
|
+
if (outputPath) {
|
|
306
|
+
writeFileSync(outputPath, decrypted);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return decrypted;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Encrypts a file using streams and writes the result to `outputPath`.
|
|
315
|
+
* Memory-efficient alternative to `encryptFile` for large files.
|
|
316
|
+
*
|
|
317
|
+
* Output format:
|
|
318
|
+
* [HEADER] + [VERSION] + [salt (16)] + [iv (12)] + [ciphertext] + [authTag (16)]
|
|
319
|
+
*
|
|
320
|
+
* @param {string} inputPath - Path to the file to encrypt
|
|
321
|
+
* @param {string} outputPath - Path to write the encrypted output to
|
|
322
|
+
* @param {string} password - Password used for key derivation
|
|
323
|
+
* @param {boolean} [gzip=true] - Whether to compress data before encryption
|
|
324
|
+
* @returns {Promise<void>}
|
|
325
|
+
* @throws {WilcoCryptError} If password is invalid
|
|
326
|
+
*/
|
|
327
|
+
wilcocrypt.encryptFileStream = async function (inputPath, outputPath, password, gzip = true) {
|
|
328
|
+
wilcocrypt._.assertPassword(password);
|
|
329
|
+
|
|
330
|
+
const salt = randomBytes(16);
|
|
331
|
+
const iv = randomBytes(12);
|
|
332
|
+
const key = scryptSync(password, salt, 32);
|
|
333
|
+
const versionBuf = Buffer.from(wilcocrypt._.VERSION);
|
|
334
|
+
|
|
335
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
336
|
+
const writeStream = createWriteStream(outputPath);
|
|
337
|
+
|
|
338
|
+
writeStream.write(wilcocrypt._.HEADER);
|
|
339
|
+
writeStream.write(versionBuf);
|
|
340
|
+
writeStream.write(salt);
|
|
341
|
+
writeStream.write(iv);
|
|
342
|
+
|
|
343
|
+
const pipelineSteps = [createReadStream(inputPath)];
|
|
344
|
+
if (gzip) pipelineSteps.push(createGzip());
|
|
345
|
+
pipelineSteps.push(cipher);
|
|
346
|
+
pipelineSteps.push(writeStream);
|
|
347
|
+
|
|
348
|
+
// end: false so we can still append the authTag after the pipeline finishes
|
|
349
|
+
await pipeline(...pipelineSteps, { end: false });
|
|
350
|
+
writeStream.end(cipher.getAuthTag());
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Decrypts an encrypted `.enc` file using streams.
|
|
355
|
+
* Memory-efficient alternative to `decryptFile` for large files.
|
|
356
|
+
* Cleans up the output file automatically if decryption or integrity check fails.
|
|
357
|
+
*
|
|
358
|
+
* @param {string} inputPath - Path to the encrypted `.enc` file
|
|
359
|
+
* @param {string} outputPath - Path to write the decrypted output to
|
|
360
|
+
* @param {string} password - Password used for decryption
|
|
361
|
+
* @param {boolean} [gzip=true] - Whether to decompress after decryption
|
|
362
|
+
* @returns {Promise<void>}
|
|
363
|
+
* @throws {WilcoCryptError} On invalid header, version mismatch, or decryption/integrity failure
|
|
364
|
+
*/
|
|
365
|
+
wilcocrypt.decryptFileStream = async function (inputPath, outputPath, password, gzip = true) {
|
|
366
|
+
wilcocrypt._.assertPassword(password);
|
|
367
|
+
|
|
368
|
+
const handle = await fsPromises.open(inputPath, 'r');
|
|
369
|
+
const versionBuf = Buffer.from(wilcocrypt._.VERSION);
|
|
370
|
+
|
|
371
|
+
const headLen = wilcocrypt._.HEADER.length;
|
|
372
|
+
const verLen = versionBuf.length;
|
|
373
|
+
|
|
374
|
+
const headerCheck = Buffer.alloc(headLen);
|
|
375
|
+
const versionCheck = Buffer.alloc(verLen);
|
|
376
|
+
const salt = Buffer.alloc(16);
|
|
377
|
+
const iv = Buffer.alloc(12);
|
|
378
|
+
|
|
379
|
+
let currentPos = 0;
|
|
380
|
+
await handle.read(headerCheck, 0, headLen, currentPos); currentPos += headLen;
|
|
381
|
+
await handle.read(versionCheck, 0, verLen, currentPos); currentPos += verLen;
|
|
382
|
+
await handle.read(salt, 0, 16, currentPos); currentPos += 16;
|
|
383
|
+
await handle.read(iv, 0, 12, currentPos); currentPos += 12;
|
|
384
|
+
|
|
385
|
+
if (!headerCheck.equals(wilcocrypt._.HEADER)) {
|
|
386
|
+
await handle.close();
|
|
387
|
+
throw new WilcoCryptError('Invalid WilcoCrypt header', 'INVALID_HEADER');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (!versionCheck.equals(versionBuf)) {
|
|
391
|
+
await handle.close();
|
|
392
|
+
throw new WilcoCryptError('Version mismatch', 'VERSION_MISMATCH');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const stats = await handle.stat();
|
|
396
|
+
const authTag = Buffer.alloc(16);
|
|
397
|
+
await handle.read(authTag, 0, 16, stats.size - 16);
|
|
398
|
+
|
|
399
|
+
const key = scryptSync(password, salt, 32);
|
|
400
|
+
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
401
|
+
decipher.setAuthTag(authTag);
|
|
402
|
+
|
|
403
|
+
const pipelineSteps = [createReadStream(inputPath, { start: currentPos, end: stats.size - 17 })];
|
|
404
|
+
pipelineSteps.push(decipher);
|
|
405
|
+
if (gzip) pipelineSteps.push(createGunzip());
|
|
406
|
+
pipelineSteps.push(createWriteStream(outputPath));
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
await pipeline(...pipelineSteps);
|
|
410
|
+
} catch {
|
|
411
|
+
await handle.close();
|
|
412
|
+
await fsPromises.unlink(outputPath);
|
|
413
|
+
throw new WilcoCryptError(
|
|
414
|
+
'Decryption failed (invalid password, corrupted data, or tampered file)',
|
|
415
|
+
'DECRYPTION_FAILED'
|
|
416
|
+
);
|
|
417
|
+
}
|
|
297
418
|
|
|
298
|
-
|
|
299
|
-
return wilcocrypt.decryptData(encryptedData, password, gzip);
|
|
419
|
+
await handle.close();
|
|
300
420
|
};
|
|
301
421
|
|
|
302
422
|
export default wilcocrypt;
|
package/types/wilcocrypt.d.ts
CHANGED
|
@@ -1,28 +1,60 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Custom error class for all WilcoCrypt-specific errors.
|
|
5
|
+
*/
|
|
3
6
|
export class WilcoCryptError extends Error {
|
|
4
7
|
code: string;
|
|
5
|
-
constructor(message: string, code?: string);
|
|
6
|
-
}
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
version: string;
|
|
9
|
+
/**
|
|
10
|
+
* @param message Human-readable error message
|
|
11
|
+
* @param code Machine-readable error code (default: WILCOCRYPT_ERROR)
|
|
12
|
+
*/
|
|
13
|
+
constructor(message: string, code?: string);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Internal helper namespace used by WilcoCrypt.
|
|
18
|
+
*/
|
|
16
19
|
export interface InternalNamespace {
|
|
20
|
+
/**
|
|
21
|
+
* WilcoCrypt version (must match during decryption).
|
|
22
|
+
*/
|
|
17
23
|
VERSION: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Minimum allowed password length.
|
|
27
|
+
*/
|
|
18
28
|
MIN_PASSWORD_LENGTH: number;
|
|
19
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Internal header used to identify valid WilcoCrypt payloads.
|
|
32
|
+
*/
|
|
33
|
+
HEADER: Buffer;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Internal error class used by WilcoCrypt.
|
|
37
|
+
*/
|
|
20
38
|
WilcoCryptError: typeof WilcoCryptError;
|
|
21
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Validates AES-256-GCM key and IV.
|
|
42
|
+
*/
|
|
22
43
|
assertKeyAndIv(key: Buffer, iv: Buffer): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Validates password strength.
|
|
47
|
+
*/
|
|
23
48
|
assertPassword(password: string): void;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Constant-time buffer comparison.
|
|
52
|
+
*/
|
|
24
53
|
constantTimeEqual(a: Buffer, b: Buffer): boolean;
|
|
25
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Encrypts raw data using AES-256-GCM.
|
|
57
|
+
*/
|
|
26
58
|
encryptData(
|
|
27
59
|
plainData: Buffer,
|
|
28
60
|
key: Buffer,
|
|
@@ -32,41 +64,123 @@ export interface InternalNamespace {
|
|
|
32
64
|
authTag: Buffer;
|
|
33
65
|
};
|
|
34
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Decrypts AES-256-GCM encrypted data.
|
|
69
|
+
*/
|
|
35
70
|
decryptData(
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
cipherBuffer: Buffer,
|
|
72
|
+
authTagBuffer: Buffer,
|
|
38
73
|
key: Buffer,
|
|
39
74
|
iv: Buffer
|
|
40
75
|
): Buffer;
|
|
41
76
|
}
|
|
42
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Main WilcoCrypt API.
|
|
80
|
+
*/
|
|
43
81
|
export interface WilcoCrypt {
|
|
44
82
|
_: InternalNamespace;
|
|
45
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Encrypts data using password-based AES-256-GCM.
|
|
86
|
+
*
|
|
87
|
+
* Output format:
|
|
88
|
+
* [HEADER (10 bytes)] + [VERSION (dynamic)] + [salt (16)] + [iv (12)] + [ciphertext] + [authTag (16)]
|
|
89
|
+
*
|
|
90
|
+
* @param plaindata Raw data to encrypt
|
|
91
|
+
* @param password Password used for key derivation
|
|
92
|
+
* @param gzip Whether to compress data before encryption (default: true)
|
|
93
|
+
* @returns Binary-encoded encrypted payload
|
|
94
|
+
*/
|
|
46
95
|
encryptData(
|
|
47
96
|
plaindata: Buffer,
|
|
48
97
|
password: string,
|
|
49
98
|
gzip?: boolean
|
|
50
99
|
): Buffer;
|
|
51
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Decrypts encrypted data using password-based AES-256-GCM.
|
|
103
|
+
*
|
|
104
|
+
* Validates internal header and version, then extracts:
|
|
105
|
+
* salt, iv, authTag and ciphertext from the binary payload.
|
|
106
|
+
*
|
|
107
|
+
* @param encryptedData Binary-encoded encrypted payload
|
|
108
|
+
* @param password Password used for decryption
|
|
109
|
+
* @param gzip Whether to decompress after decryption (default: true)
|
|
110
|
+
* @returns Decrypted raw data
|
|
111
|
+
*
|
|
112
|
+
* @throws WilcoCryptError on:
|
|
113
|
+
* - invalid header
|
|
114
|
+
* - version mismatch
|
|
115
|
+
* - wrong password
|
|
116
|
+
* - corrupted data
|
|
117
|
+
*/
|
|
52
118
|
decryptData(
|
|
53
119
|
encryptedData: Buffer,
|
|
54
120
|
password: string,
|
|
55
121
|
gzip?: boolean
|
|
56
122
|
): Buffer;
|
|
57
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Encrypts a file and writes `<filePath>.enc`.
|
|
126
|
+
*/
|
|
58
127
|
encryptFile(
|
|
59
128
|
filePath: string,
|
|
60
129
|
password: string,
|
|
61
130
|
gzip?: boolean
|
|
62
131
|
): void;
|
|
63
132
|
|
|
64
|
-
|
|
65
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Decrypts a `.enc` file.
|
|
135
|
+
*
|
|
136
|
+
* If `outputPath` is provided, the decrypted data is written to that file
|
|
137
|
+
* and `undefined` is returned. Otherwise the decrypted Buffer is returned.
|
|
138
|
+
*/
|
|
139
|
+
decryptFile(filePath: string, password: string, outputPath: string, gzip?: boolean): undefined;
|
|
140
|
+
decryptFile(filePath: string, password: string, gzip?: boolean): Buffer;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Encrypts a file using streams and writes the result to `outputPath`.
|
|
144
|
+
* Memory-efficient alternative to `encryptFile` for large files.
|
|
145
|
+
*
|
|
146
|
+
* @param inputPath Path to the file to encrypt
|
|
147
|
+
* @param outputPath Path to write the encrypted output to
|
|
148
|
+
* @param password Password used for key derivation
|
|
149
|
+
* @param gzip Whether to compress data before encryption (default: true)
|
|
150
|
+
*/
|
|
151
|
+
encryptFileStream(
|
|
152
|
+
inputPath: string,
|
|
153
|
+
outputPath: string,
|
|
66
154
|
password: string,
|
|
67
155
|
gzip?: boolean
|
|
68
|
-
):
|
|
156
|
+
): Promise<void>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Decrypts an encrypted file using streams.
|
|
160
|
+
* Memory-efficient alternative to `decryptFile` for large files.
|
|
161
|
+
* Cleans up the output file automatically if decryption or integrity check fails.
|
|
162
|
+
*
|
|
163
|
+
* @param inputPath Path to the encrypted file
|
|
164
|
+
* @param outputPath Path to write the decrypted output to
|
|
165
|
+
* @param password Password used for decryption
|
|
166
|
+
* @param gzip Whether to decompress after decryption (default: true)
|
|
167
|
+
*
|
|
168
|
+
* @throws WilcoCryptError on:
|
|
169
|
+
* - invalid header
|
|
170
|
+
* - version mismatch
|
|
171
|
+
* - decryption/integrity failure
|
|
172
|
+
*/
|
|
173
|
+
decryptFileStream(
|
|
174
|
+
inputPath: string,
|
|
175
|
+
outputPath: string,
|
|
176
|
+
password: string,
|
|
177
|
+
gzip?: boolean
|
|
178
|
+
): Promise<void>;
|
|
69
179
|
}
|
|
70
180
|
|
|
181
|
+
/**
|
|
182
|
+
* WilcoCrypt main instance.
|
|
183
|
+
*/
|
|
71
184
|
declare const wilcocrypt: WilcoCrypt;
|
|
185
|
+
|
|
72
186
|
export default wilcocrypt;
|