@time-file/browser-file-crypto 1.0.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/LICENSE +21 -0
- package/README.ko.md +287 -0
- package/README.md +292 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +726 -0
- package/dist/index.mjs +334 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +68 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-file-crypto
|
|
3
|
+
*
|
|
4
|
+
* Zero-dependency file encryption for browsers using Web Crypto API.
|
|
5
|
+
* Provides AES-256-GCM encryption with password or keyfile-based keys.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
* @module browser-file-crypto
|
|
9
|
+
* @since 1.0.0
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {
|
|
14
|
+
* encryptFile,
|
|
15
|
+
* decryptFile,
|
|
16
|
+
* generateKeyFile,
|
|
17
|
+
* getEncryptionType
|
|
18
|
+
* } from '@time-file/browser-file-crypto';
|
|
19
|
+
*
|
|
20
|
+
* // Password-based encryption
|
|
21
|
+
* const encrypted = await encryptFile(file, {
|
|
22
|
+
* password: 'my-secret',
|
|
23
|
+
* onProgress: ({ phase, progress }) => console.log(`${phase}: ${progress}%`)
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Keyfile-based encryption
|
|
27
|
+
* const keyFile = generateKeyFile();
|
|
28
|
+
* const encrypted = await encryptFile(file, { keyData: keyFile.key });
|
|
29
|
+
*
|
|
30
|
+
* // Decryption
|
|
31
|
+
* const decrypted = await decryptFile(encrypted, { password: 'my-secret' });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Algorithm identifier string for AES-GCM.
|
|
37
|
+
*/
|
|
38
|
+
export declare const ALGORITHM: "AES-GCM";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* AES-GCM authentication tag length in bytes.
|
|
42
|
+
* 16 bytes (128 bits) is the default and recommended tag size.
|
|
43
|
+
*/
|
|
44
|
+
export declare const AUTH_TAG_LENGTH = 16;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Computes SHA-256 hash of a keyfile's key data.
|
|
48
|
+
*
|
|
49
|
+
* @description
|
|
50
|
+
* Generates a SHA-256 hash of the key data for server-side verification.
|
|
51
|
+
* This allows the server to verify that the client has the correct keyfile
|
|
52
|
+
* without ever seeing the actual key.
|
|
53
|
+
*
|
|
54
|
+
* Use case: Store the hash on the server, then verify client-provided
|
|
55
|
+
* hash matches before allowing access to encrypted content.
|
|
56
|
+
*
|
|
57
|
+
* @param keyData - Base64-encoded key string (from KeyFile.key)
|
|
58
|
+
* @returns Promise resolving to hex-encoded SHA-256 hash
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const keyFile = generateKeyFile();
|
|
63
|
+
* const hash = await computeKeyFileHash(keyFile.key);
|
|
64
|
+
* console.log(hash); // '3a7bd3e2c1f8...' (64 hex characters)
|
|
65
|
+
*
|
|
66
|
+
* // Send hash to server for storage
|
|
67
|
+
* await fetch('/api/store-key-hash', {
|
|
68
|
+
* method: 'POST',
|
|
69
|
+
* body: JSON.stringify({ hash })
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Later, verify keyfile by comparing hashes
|
|
73
|
+
* const uploadedHash = await computeKeyFileHash(uploadedKeyFile.key);
|
|
74
|
+
* const isValid = uploadedHash === storedHash;
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @since 1.0.0
|
|
78
|
+
*/
|
|
79
|
+
export declare function computeKeyFileHash(keyData: string): Promise<string>;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Custom error class for crypto operations.
|
|
83
|
+
*
|
|
84
|
+
* @description
|
|
85
|
+
* Provides structured error handling with error codes for programmatic handling.
|
|
86
|
+
* Each error includes a code that can be used for i18n or specific error handling.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* try {
|
|
91
|
+
* await decryptFile(data, { password: 'wrong' });
|
|
92
|
+
* } catch (error) {
|
|
93
|
+
* if (error instanceof CryptoError) {
|
|
94
|
+
* console.log(error.code); // 'INVALID_PASSWORD'
|
|
95
|
+
* console.log(error.message); // 'Decryption failed: incorrect password.'
|
|
96
|
+
*
|
|
97
|
+
* switch (error.code) {
|
|
98
|
+
* case 'INVALID_PASSWORD':
|
|
99
|
+
* showPasswordError();
|
|
100
|
+
* break;
|
|
101
|
+
* case 'INVALID_ENCRYPTED_DATA':
|
|
102
|
+
* showCorruptedFileError();
|
|
103
|
+
* break;
|
|
104
|
+
* }
|
|
105
|
+
* }
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* @see {@link CryptoErrorCode} for all available error codes
|
|
110
|
+
* @since 1.0.0
|
|
111
|
+
*/
|
|
112
|
+
export declare class CryptoError extends Error {
|
|
113
|
+
/** Error code for programmatic handling */
|
|
114
|
+
readonly code: CryptoErrorCode;
|
|
115
|
+
/**
|
|
116
|
+
* Creates a new CryptoError.
|
|
117
|
+
*
|
|
118
|
+
* @param code - Error code identifying the type of error
|
|
119
|
+
* @param message - Optional custom message (defaults to predefined message)
|
|
120
|
+
*/
|
|
121
|
+
constructor(code: CryptoErrorCode, message?: string);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Error handling for browser-file-crypto.
|
|
126
|
+
*
|
|
127
|
+
* @module errors
|
|
128
|
+
* @since 1.0.0
|
|
129
|
+
*/
|
|
130
|
+
/**
|
|
131
|
+
* Error codes for CryptoError.
|
|
132
|
+
*
|
|
133
|
+
* @description
|
|
134
|
+
* - `INVALID_INPUT`: Input is not a valid File, Blob, or ArrayBuffer
|
|
135
|
+
* - `PASSWORD_REQUIRED`: Password is required but not provided
|
|
136
|
+
* - `KEYFILE_REQUIRED`: Keyfile is required but not provided
|
|
137
|
+
* - `INVALID_PASSWORD`: Decryption failed due to incorrect password
|
|
138
|
+
* - `INVALID_KEYFILE`: Decryption failed due to incorrect keyfile
|
|
139
|
+
* - `INVALID_ENCRYPTED_DATA`: Data is corrupted or not encrypted with this library
|
|
140
|
+
* - `ENCRYPTION_FAILED`: Encryption operation failed
|
|
141
|
+
* - `DECRYPTION_FAILED`: Decryption operation failed
|
|
142
|
+
* - `DOWNLOAD_FAILED`: File download failed
|
|
143
|
+
* - `UNSUPPORTED_FORMAT`: Encrypted file format is not supported
|
|
144
|
+
*/
|
|
145
|
+
export declare type CryptoErrorCode = 'INVALID_INPUT' | 'PASSWORD_REQUIRED' | 'KEYFILE_REQUIRED' | 'INVALID_PASSWORD' | 'INVALID_KEYFILE' | 'INVALID_ENCRYPTED_DATA' | 'ENCRYPTION_FAILED' | 'DECRYPTION_FAILED' | 'DOWNLOAD_FAILED' | 'UNSUPPORTED_FORMAT';
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Decrypts a file that was encrypted with encryptFile.
|
|
149
|
+
*
|
|
150
|
+
* @description
|
|
151
|
+
* Automatically detects whether the file was encrypted with password or keyfile
|
|
152
|
+
* based on the marker byte, then decrypts accordingly.
|
|
153
|
+
*
|
|
154
|
+
* For password-encrypted files:
|
|
155
|
+
* - Extracts salt and IV from header
|
|
156
|
+
* - Derives key using PBKDF2
|
|
157
|
+
* - Decrypts with AES-GCM
|
|
158
|
+
*
|
|
159
|
+
* For keyfile-encrypted files:
|
|
160
|
+
* - Extracts IV from header
|
|
161
|
+
* - Imports key directly
|
|
162
|
+
* - Decrypts with AES-GCM
|
|
163
|
+
*
|
|
164
|
+
* @param encrypted - The encrypted data (Blob or ArrayBuffer)
|
|
165
|
+
* @param options - Decryption options including password or keyData
|
|
166
|
+
* @returns Promise resolving to decrypted Blob
|
|
167
|
+
*
|
|
168
|
+
* @throws {CryptoError} When password is required but not provided (PASSWORD_REQUIRED)
|
|
169
|
+
* @throws {CryptoError} When keyfile is required but not provided (KEYFILE_REQUIRED)
|
|
170
|
+
* @throws {CryptoError} When password is incorrect (INVALID_PASSWORD)
|
|
171
|
+
* @throws {CryptoError} When keyfile is incorrect (INVALID_KEYFILE)
|
|
172
|
+
* @throws {CryptoError} When data is corrupted (INVALID_ENCRYPTED_DATA)
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // Password-based decryption
|
|
177
|
+
* try {
|
|
178
|
+
* const decrypted = await decryptFile(encryptedBlob, {
|
|
179
|
+
* password: 'my-secret',
|
|
180
|
+
* onProgress: ({ phase, progress }) => console.log(`${phase}: ${progress}%`)
|
|
181
|
+
* });
|
|
182
|
+
* } catch (error) {
|
|
183
|
+
* if (error instanceof CryptoError && error.code === 'INVALID_PASSWORD') {
|
|
184
|
+
* console.log('Wrong password!');
|
|
185
|
+
* }
|
|
186
|
+
* }
|
|
187
|
+
*
|
|
188
|
+
* // Keyfile-based decryption
|
|
189
|
+
* const decrypted = await decryptFile(encryptedBlob, {
|
|
190
|
+
* keyData: keyFile.key
|
|
191
|
+
* });
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @see {@link encryptFile} for encryption
|
|
195
|
+
* @see {@link getEncryptionType} for detecting encryption method
|
|
196
|
+
* @since 1.0.0
|
|
197
|
+
*/
|
|
198
|
+
export declare function decryptFile(encrypted: Blob | ArrayBuffer, options: DecryptOptions): Promise<Blob>;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Options for file decryption.
|
|
202
|
+
*
|
|
203
|
+
* @description
|
|
204
|
+
* The correct option (password or keyData) must match the encryption method used.
|
|
205
|
+
* Use `getEncryptionType()` to detect which method was used.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* const options: DecryptOptions = {
|
|
210
|
+
* password: 'my-secret-password',
|
|
211
|
+
* onProgress: ({ phase, progress }) => {
|
|
212
|
+
* if (phase === 'complete') console.log('Done!');
|
|
213
|
+
* }
|
|
214
|
+
* };
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export declare interface DecryptOptions {
|
|
218
|
+
/** Password for decryption (required for password-encrypted files) */
|
|
219
|
+
password?: string;
|
|
220
|
+
/** Base64-encoded key data (required for keyfile-encrypted files) */
|
|
221
|
+
keyData?: string;
|
|
222
|
+
/** Progress callback for UI updates */
|
|
223
|
+
onProgress?: ProgressCallback;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Downloads an encrypted file from URL, decrypts it, and saves to disk.
|
|
228
|
+
*
|
|
229
|
+
* @description
|
|
230
|
+
* Combines file download, decryption, and save into a single operation.
|
|
231
|
+
* Progress callback reports both download and decryption phases.
|
|
232
|
+
*
|
|
233
|
+
* Phases:
|
|
234
|
+
* 1. `downloading` (0-50%): Fetching file from URL
|
|
235
|
+
* 2. `deriving_key` (50-60%): Key derivation (password mode only)
|
|
236
|
+
* 3. `decrypting` (60-95%): AES-GCM decryption
|
|
237
|
+
* 4. `complete` (100%): File saved
|
|
238
|
+
*
|
|
239
|
+
* Note: This function uses browser APIs (fetch, URL.createObjectURL, document.createElement)
|
|
240
|
+
* and will not work in Node.js environments.
|
|
241
|
+
*
|
|
242
|
+
* @param url - URL of the encrypted file to download
|
|
243
|
+
* @param options - Options including password/keyData and fileName
|
|
244
|
+
* @returns Promise that resolves when file is saved
|
|
245
|
+
*
|
|
246
|
+
* @throws {CryptoError} When download fails (DOWNLOAD_FAILED)
|
|
247
|
+
* @throws {CryptoError} When decryption fails (see decryptFile errors)
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* await downloadAndDecrypt('https://example.com/secret.enc', {
|
|
252
|
+
* password: 'my-secret',
|
|
253
|
+
* fileName: 'document.pdf',
|
|
254
|
+
* onProgress: ({ phase, progress }) => {
|
|
255
|
+
* console.log(`${phase}: ${progress}%`);
|
|
256
|
+
* // downloading: 25%
|
|
257
|
+
* // downloading: 50%
|
|
258
|
+
* // deriving_key: 55%
|
|
259
|
+
* // decrypting: 80%
|
|
260
|
+
* // complete: 100%
|
|
261
|
+
* }
|
|
262
|
+
* });
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* @see {@link decryptFile} for decryption only
|
|
266
|
+
* @since 1.0.0
|
|
267
|
+
*/
|
|
268
|
+
export declare function downloadAndDecrypt(url: string, options: DownloadDecryptOptions): Promise<void>;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Options for download and decrypt operation.
|
|
272
|
+
*
|
|
273
|
+
* @description
|
|
274
|
+
* Extends DecryptOptions with fileName for the downloaded file.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* await downloadAndDecrypt('https://example.com/file.enc', {
|
|
279
|
+
* password: 'secret',
|
|
280
|
+
* fileName: 'document.pdf',
|
|
281
|
+
* onProgress: ({ phase, progress }) => console.log(`${phase}: ${progress}%`)
|
|
282
|
+
* });
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export declare interface DownloadDecryptOptions extends DecryptOptions {
|
|
286
|
+
/** File name to use when saving the decrypted file */
|
|
287
|
+
fileName: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Downloads a keyfile as a JSON file with customizable extension.
|
|
292
|
+
*
|
|
293
|
+
* @description
|
|
294
|
+
* Creates a downloadable JSON file containing the keyfile data.
|
|
295
|
+
* The file extension can be customized (default: .key).
|
|
296
|
+
*
|
|
297
|
+
* Note: This function uses browser APIs (URL.createObjectURL, document.createElement)
|
|
298
|
+
* and will not work in Node.js or Web Worker environments.
|
|
299
|
+
*
|
|
300
|
+
* @param keyData - Base64-encoded key string (from KeyFile.key)
|
|
301
|
+
* @param fileName - Name for the downloaded file (without extension)
|
|
302
|
+
* @param extension - File extension without dot (default: 'key')
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const keyFile = generateKeyFile();
|
|
307
|
+
*
|
|
308
|
+
* // Downloads as 'my-secret-key.key' (default)
|
|
309
|
+
* downloadKeyFile(keyFile.key, 'my-secret-key');
|
|
310
|
+
*
|
|
311
|
+
* // Downloads as 'my-secret-key.tfkey' (custom extension)
|
|
312
|
+
* downloadKeyFile(keyFile.key, 'my-secret-key', 'tfkey');
|
|
313
|
+
*
|
|
314
|
+
* // The downloaded file contains:
|
|
315
|
+
* // {
|
|
316
|
+
* // "version": 1,
|
|
317
|
+
* // "algorithm": "AES-256-GCM",
|
|
318
|
+
* // "key": "base64...",
|
|
319
|
+
* // "createdAt": "2025-01-01T00:00:00.000Z"
|
|
320
|
+
* // }
|
|
321
|
+
* ```
|
|
322
|
+
*
|
|
323
|
+
* @since 1.0.0
|
|
324
|
+
*/
|
|
325
|
+
export declare function downloadKeyFile(keyData: string, fileName: string, extension?: string): void;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Encrypts a file using AES-256-GCM with password-based key derivation.
|
|
329
|
+
*
|
|
330
|
+
* @description
|
|
331
|
+
* Uses PBKDF2 with 100,000 iterations to derive a 256-bit key from the password.
|
|
332
|
+
* Each encryption generates a unique random salt (16 bytes) and IV (12 bytes).
|
|
333
|
+
* The output format is: [marker(1)] + [salt(16)] + [iv(12)] + [ciphertext + auth tag].
|
|
334
|
+
*
|
|
335
|
+
* For keyfile-based encryption, the key is used directly without derivation.
|
|
336
|
+
* The output format is: [marker(1)] + [iv(12)] + [ciphertext + auth tag].
|
|
337
|
+
*
|
|
338
|
+
* @param file - The file to encrypt (File, Blob, or ArrayBuffer)
|
|
339
|
+
* @param options - Encryption options including password or keyData
|
|
340
|
+
* @returns Promise resolving to encrypted Blob with 'application/octet-stream' MIME type
|
|
341
|
+
*
|
|
342
|
+
* @throws {CryptoError} When neither password nor keyData is provided (PASSWORD_REQUIRED)
|
|
343
|
+
* @throws {CryptoError} When input is invalid (INVALID_INPUT)
|
|
344
|
+
* @throws {CryptoError} When encryption fails (ENCRYPTION_FAILED)
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* // Password-based encryption
|
|
349
|
+
* const encrypted = await encryptFile(file, {
|
|
350
|
+
* password: 'my-secret',
|
|
351
|
+
* onProgress: ({ phase, progress }) => console.log(`${phase}: ${progress}%`)
|
|
352
|
+
* });
|
|
353
|
+
*
|
|
354
|
+
* // Keyfile-based encryption
|
|
355
|
+
* const keyFile = generateKeyFile();
|
|
356
|
+
* const encrypted = await encryptFile(file, {
|
|
357
|
+
* keyData: keyFile.key,
|
|
358
|
+
* onProgress: ({ progress }) => updateProgressBar(progress)
|
|
359
|
+
* });
|
|
360
|
+
* ```
|
|
361
|
+
*
|
|
362
|
+
* @see {@link decryptFile} for decryption
|
|
363
|
+
* @see {@link generateKeyFile} for creating keyfiles
|
|
364
|
+
* @since 1.0.0
|
|
365
|
+
*/
|
|
366
|
+
export declare function encryptFile(file: File | Blob | ArrayBuffer, options: EncryptOptions): Promise<Blob>;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Encryption marker byte for keyfile-based encryption.
|
|
370
|
+
* Used to identify the encryption method when decrypting.
|
|
371
|
+
*/
|
|
372
|
+
export declare const ENCRYPTION_MARKER_KEYFILE = 2;
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Encryption marker byte for password-based encryption.
|
|
376
|
+
* Used to identify the encryption method when decrypting.
|
|
377
|
+
*/
|
|
378
|
+
export declare const ENCRYPTION_MARKER_PASSWORD = 1;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Encryption type detected from encrypted data.
|
|
382
|
+
*
|
|
383
|
+
* @description
|
|
384
|
+
* - `password`: File was encrypted with a password (marker byte 0x01)
|
|
385
|
+
* - `keyfile`: File was encrypted with a keyfile (marker byte 0x02)
|
|
386
|
+
* - `unknown`: Unrecognized format or not encrypted with this library
|
|
387
|
+
*/
|
|
388
|
+
export declare type EncryptionType = 'password' | 'keyfile' | 'unknown';
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Options for file encryption.
|
|
392
|
+
*
|
|
393
|
+
* @description
|
|
394
|
+
* Either `password` or `keyData` must be provided, but not both.
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* // Password-based encryption
|
|
399
|
+
* const options: EncryptOptions = {
|
|
400
|
+
* password: 'my-secret-password',
|
|
401
|
+
* onProgress: ({ progress }) => console.log(`${progress}%`)
|
|
402
|
+
* };
|
|
403
|
+
*
|
|
404
|
+
* // Keyfile-based encryption
|
|
405
|
+
* const options: EncryptOptions = {
|
|
406
|
+
* keyData: keyFile.key,
|
|
407
|
+
* onProgress: ({ progress }) => console.log(`${progress}%`)
|
|
408
|
+
* };
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
export declare interface EncryptOptions {
|
|
412
|
+
/** Password for encryption (required if keyData not provided) */
|
|
413
|
+
password?: string;
|
|
414
|
+
/** Base64-encoded key data from keyfile (required if password not provided) */
|
|
415
|
+
keyData?: string;
|
|
416
|
+
/** Progress callback for UI updates */
|
|
417
|
+
onProgress?: ProgressCallback;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Generates a new keyfile with a 256-bit random key.
|
|
422
|
+
*
|
|
423
|
+
* @description
|
|
424
|
+
* Creates a cryptographically secure 256-bit (32 bytes) random key
|
|
425
|
+
* using crypto.getRandomValues(). The key is returned as a KeyFile
|
|
426
|
+
* object with metadata including version, algorithm, and creation timestamp.
|
|
427
|
+
*
|
|
428
|
+
* The generated key can be used directly with encryptFile() and decryptFile()
|
|
429
|
+
* without any key derivation (unlike password-based encryption).
|
|
430
|
+
*
|
|
431
|
+
* @returns KeyFile object containing the generated key
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const keyFile = generateKeyFile();
|
|
436
|
+
* console.log(keyFile);
|
|
437
|
+
* // {
|
|
438
|
+
* // version: 1,
|
|
439
|
+
* // algorithm: 'AES-256-GCM',
|
|
440
|
+
* // key: 'base64-encoded-32-bytes...',
|
|
441
|
+
* // createdAt: '2025-01-01T12:00:00.000Z'
|
|
442
|
+
* // }
|
|
443
|
+
*
|
|
444
|
+
* // Use for encryption
|
|
445
|
+
* const encrypted = await encryptFile(file, { keyData: keyFile.key });
|
|
446
|
+
*
|
|
447
|
+
* // Save keyfile for later
|
|
448
|
+
* downloadKeyFile(keyFile.key, 'my-encryption-key');
|
|
449
|
+
* ```
|
|
450
|
+
*
|
|
451
|
+
* @see {@link downloadKeyFile} for saving the keyfile
|
|
452
|
+
* @see {@link parseKeyFile} for loading a saved keyfile
|
|
453
|
+
* @since 1.0.0
|
|
454
|
+
*/
|
|
455
|
+
export declare function generateKeyFile(): KeyFile;
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Generates a cryptographically secure random password.
|
|
459
|
+
*
|
|
460
|
+
* @description
|
|
461
|
+
* Creates a random password using crypto.getRandomValues() for
|
|
462
|
+
* cryptographic randomness. The password includes:
|
|
463
|
+
* - Uppercase letters (A-Z)
|
|
464
|
+
* - Lowercase letters (a-z)
|
|
465
|
+
* - Numbers (0-9)
|
|
466
|
+
* - Special characters (!@#$%^&*)
|
|
467
|
+
*
|
|
468
|
+
* @param length - Password length (default: 16, min: 8, max: 128)
|
|
469
|
+
* @returns Random password string
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* ```typescript
|
|
473
|
+
* const password = generateRandomPassword();
|
|
474
|
+
* console.log(password); // e.g., 'Kx9#mP2$vL5@nQ8!'
|
|
475
|
+
*
|
|
476
|
+
* const longPassword = generateRandomPassword(32);
|
|
477
|
+
* console.log(longPassword.length); // 32
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* @since 1.0.0
|
|
481
|
+
*/
|
|
482
|
+
export declare function generateRandomPassword(length?: number): string;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Detects the encryption type of encrypted data.
|
|
486
|
+
*
|
|
487
|
+
* @description
|
|
488
|
+
* Reads the first byte (marker) of the encrypted data to determine
|
|
489
|
+
* whether it was encrypted with a password or keyfile.
|
|
490
|
+
*
|
|
491
|
+
* - Marker 0x01: Password-based encryption
|
|
492
|
+
* - Marker 0x02: Keyfile-based encryption
|
|
493
|
+
* - Other: Unknown format
|
|
494
|
+
*
|
|
495
|
+
* @param data - The encrypted data (Blob or ArrayBuffer)
|
|
496
|
+
* @returns Promise resolving to encryption type
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* ```typescript
|
|
500
|
+
* const type = await getEncryptionType(encryptedBlob);
|
|
501
|
+
*
|
|
502
|
+
* switch (type) {
|
|
503
|
+
* case 'password':
|
|
504
|
+
* // Show password input
|
|
505
|
+
* break;
|
|
506
|
+
* case 'keyfile':
|
|
507
|
+
* // Show keyfile picker
|
|
508
|
+
* break;
|
|
509
|
+
* case 'unknown':
|
|
510
|
+
* // Show error: not encrypted with this library
|
|
511
|
+
* break;
|
|
512
|
+
* }
|
|
513
|
+
* ```
|
|
514
|
+
*
|
|
515
|
+
* @see {@link isEncryptedFile} for simple encryption check
|
|
516
|
+
* @since 1.0.0
|
|
517
|
+
*/
|
|
518
|
+
export declare function getEncryptionType(data: Blob | ArrayBuffer): Promise<EncryptionType>;
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Hash algorithm used in PBKDF2 key derivation.
|
|
522
|
+
*/
|
|
523
|
+
export declare const HASH_ALGORITHM: "SHA-256";
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Type guard to check if an error is a CryptoError.
|
|
527
|
+
*
|
|
528
|
+
* @param error - The error to check
|
|
529
|
+
* @returns True if the error is a CryptoError
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* ```typescript
|
|
533
|
+
* try {
|
|
534
|
+
* await decryptFile(data, options);
|
|
535
|
+
* } catch (error) {
|
|
536
|
+
* if (isCryptoError(error)) {
|
|
537
|
+
* console.log(error.code);
|
|
538
|
+
* }
|
|
539
|
+
* }
|
|
540
|
+
* ```
|
|
541
|
+
*/
|
|
542
|
+
export declare function isCryptoError(error: unknown): error is CryptoError;
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Checks if data appears to be encrypted with this library.
|
|
546
|
+
*
|
|
547
|
+
* @description
|
|
548
|
+
* Performs a quick check to determine if the data was likely encrypted
|
|
549
|
+
* with browser-file-crypto. This checks:
|
|
550
|
+
* 1. The marker byte is valid (0x01 or 0x02)
|
|
551
|
+
* 2. The data meets minimum size requirements
|
|
552
|
+
*
|
|
553
|
+
* Note: This is not a cryptographic verification. It only checks
|
|
554
|
+
* the format markers and size constraints.
|
|
555
|
+
*
|
|
556
|
+
* @param data - The data to check (Blob or ArrayBuffer)
|
|
557
|
+
* @returns Promise resolving to true if data appears to be encrypted
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```typescript
|
|
561
|
+
* const file = event.target.files[0];
|
|
562
|
+
* const isEncrypted = await isEncryptedFile(file);
|
|
563
|
+
*
|
|
564
|
+
* if (isEncrypted) {
|
|
565
|
+
* showDecryptionUI();
|
|
566
|
+
* } else {
|
|
567
|
+
* showEncryptionUI();
|
|
568
|
+
* }
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @since 1.0.0
|
|
572
|
+
*/
|
|
573
|
+
export declare function isEncryptedFile(data: Blob | ArrayBuffer): Promise<boolean>;
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Initialization vector length in bytes for AES-GCM.
|
|
577
|
+
* 12 bytes (96 bits) is the recommended IV size for AES-GCM per NIST SP 800-38D.
|
|
578
|
+
*/
|
|
579
|
+
export declare const IV_LENGTH = 12;
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* AES key length in bits.
|
|
583
|
+
* 256 bits provides the highest security level for AES.
|
|
584
|
+
*/
|
|
585
|
+
export declare const KEY_LENGTH = 256;
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Key file structure for keyfile-based encryption.
|
|
589
|
+
*
|
|
590
|
+
* @description
|
|
591
|
+
* Contains a 256-bit random key for direct AES-256-GCM encryption.
|
|
592
|
+
* No key derivation is needed - the key is used directly.
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* const keyFile = generateKeyFile();
|
|
597
|
+
* // {
|
|
598
|
+
* // version: 1,
|
|
599
|
+
* // algorithm: 'AES-256-GCM',
|
|
600
|
+
* // key: 'base64-encoded-32-bytes',
|
|
601
|
+
* // createdAt: '2025-01-01T00:00:00.000Z'
|
|
602
|
+
* // }
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
export declare interface KeyFile {
|
|
606
|
+
/** Key file format version */
|
|
607
|
+
version: 1;
|
|
608
|
+
/** Encryption algorithm identifier */
|
|
609
|
+
algorithm: 'AES-256-GCM';
|
|
610
|
+
/** Base64-encoded 256-bit key */
|
|
611
|
+
key: string;
|
|
612
|
+
/** ISO 8601 timestamp of key creation */
|
|
613
|
+
createdAt: string;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Key file raw key length in bytes (256-bit).
|
|
618
|
+
* Matches the AES-256 key size requirement.
|
|
619
|
+
*/
|
|
620
|
+
export declare const KEYFILE_KEY_LENGTH = 32;
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Minimum encrypted file size for keyfile-based encryption.
|
|
624
|
+
* Header (1 + 12 = 13 bytes) + Auth tag (16 bytes) = 29 bytes.
|
|
625
|
+
*/
|
|
626
|
+
export declare const MIN_ENCRYPTED_SIZE_KEYFILE: number;
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Minimum encrypted file size for password-based encryption.
|
|
630
|
+
* Header (1 + 16 + 12 = 29 bytes) + Auth tag (16 bytes) = 45 bytes.
|
|
631
|
+
*/
|
|
632
|
+
export declare const MIN_ENCRYPTED_SIZE_PASSWORD: number;
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Parses a keyfile from JSON string content.
|
|
636
|
+
*
|
|
637
|
+
* @description
|
|
638
|
+
* Validates and parses a JSON string into a KeyFile object.
|
|
639
|
+
* Performs validation to ensure:
|
|
640
|
+
* - Valid JSON format
|
|
641
|
+
* - Required fields present (version, algorithm, key)
|
|
642
|
+
* - Correct version (1)
|
|
643
|
+
* - Correct algorithm ('AES-256-GCM')
|
|
644
|
+
* - Key is a non-empty string
|
|
645
|
+
*
|
|
646
|
+
* @param content - JSON string content of the keyfile
|
|
647
|
+
* @returns KeyFile object if valid, null if invalid
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* ```typescript
|
|
651
|
+
* // From file input
|
|
652
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
653
|
+
* fileInput.addEventListener('change', async (e) => {
|
|
654
|
+
* const file = e.target.files[0];
|
|
655
|
+
* const content = await file.text();
|
|
656
|
+
* const keyFile = parseKeyFile(content);
|
|
657
|
+
*
|
|
658
|
+
* if (keyFile) {
|
|
659
|
+
* const decrypted = await decryptFile(encrypted, { keyData: keyFile.key });
|
|
660
|
+
* } else {
|
|
661
|
+
* console.error('Invalid keyfile format');
|
|
662
|
+
* }
|
|
663
|
+
* });
|
|
664
|
+
* ```
|
|
665
|
+
*
|
|
666
|
+
* @see {@link generateKeyFile} for creating keyfiles
|
|
667
|
+
* @since 1.0.0
|
|
668
|
+
*/
|
|
669
|
+
export declare function parseKeyFile(content: string): KeyFile | null;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* PBKDF2 iteration count for key derivation.
|
|
673
|
+
* 100,000 iterations balance security and performance.
|
|
674
|
+
* Higher values increase resistance to brute-force attacks.
|
|
675
|
+
*/
|
|
676
|
+
export declare const PBKDF2_ITERATIONS = 100000;
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Progress information for encryption/decryption operations.
|
|
680
|
+
*
|
|
681
|
+
* @example
|
|
682
|
+
* ```typescript
|
|
683
|
+
* onProgress: ({ phase, progress }) => {
|
|
684
|
+
* console.log(`${phase}: ${progress}%`);
|
|
685
|
+
* }
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
export declare interface Progress {
|
|
689
|
+
/** Current phase of the operation */
|
|
690
|
+
phase: ProgressPhase;
|
|
691
|
+
/** Progress percentage (0-100) */
|
|
692
|
+
progress: number;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Callback function for progress updates.
|
|
697
|
+
*
|
|
698
|
+
* @param progress - Current progress information
|
|
699
|
+
*/
|
|
700
|
+
export declare type ProgressCallback = (progress: Progress) => void;
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Core type definitions for browser-file-crypto.
|
|
704
|
+
*
|
|
705
|
+
* @module types
|
|
706
|
+
* @since 1.0.0
|
|
707
|
+
*/
|
|
708
|
+
/**
|
|
709
|
+
* Progress phase during encryption/decryption operations.
|
|
710
|
+
*
|
|
711
|
+
* @description
|
|
712
|
+
* - `deriving_key`: PBKDF2 key derivation in progress (password mode)
|
|
713
|
+
* - `encrypting`: AES-GCM encryption in progress
|
|
714
|
+
* - `decrypting`: AES-GCM decryption in progress
|
|
715
|
+
* - `downloading`: File download in progress (downloadAndDecrypt)
|
|
716
|
+
* - `complete`: Operation finished successfully
|
|
717
|
+
*/
|
|
718
|
+
export declare type ProgressPhase = 'deriving_key' | 'encrypting' | 'decrypting' | 'downloading' | 'complete';
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Salt length in bytes for PBKDF2 key derivation.
|
|
722
|
+
* 16 bytes (128 bits) provides sufficient randomness to prevent rainbow table attacks.
|
|
723
|
+
*/
|
|
724
|
+
export declare const SALT_LENGTH = 16;
|
|
725
|
+
|
|
726
|
+
export { }
|