@kryklin/darkstar-crypt-node 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.
Files changed (2) hide show
  1. package/darkstar_crypt.js +559 -0
  2. package/package.json +23 -0
@@ -0,0 +1,559 @@
1
+
2
+ const crypto = globalThis.crypto;
3
+
4
+ /**
5
+ * DarkstarCrypt - Advanced Encryption Implementation
6
+ *
7
+ * This class implements the V2 Darkstar encryption, featuring:
8
+ * - 12-layer obfuscation pipeline (dynamic per-word)
9
+ * - Mulberry32 deterministic PRNG
10
+ * - AES-256-CBC encryption with PBKDF2 key derivation
11
+ * - Self-validating checksums
12
+ *
13
+ * @version 1.0.0
14
+ */
15
+ export class DarkstarCrypt {
16
+ ITERATIONS_V1 = 1000;
17
+ ITERATIONS_V2 = 600000;
18
+ KEY_SIZE = 256 / 32;
19
+ SALT_SIZE_BYTES = 128 / 8;
20
+ IV_SIZE_BYTES = 128 / 8;
21
+
22
+ constructor() {
23
+ this.obfuscationFunctionsV2 = [
24
+ this.obfuscateByReversingV2.bind(this),
25
+ this.obfuscateWithAtbashCipherV2.bind(this),
26
+ this.obfuscateToCharCodesV2.bind(this),
27
+ this.obfuscateToBinaryV2.bind(this),
28
+ this.obfuscateWithCaesarCipherV2.bind(this),
29
+ this.obfuscateBySwappingAdjacentBytesV2.bind(this),
30
+ this.obfuscateByShufflingV2.bind(this),
31
+ this.obfuscateWithXORV2.bind(this),
32
+ this.obfuscateByInterleavingV2.bind(this),
33
+ this.obfuscateWithVigenereCipherV2.bind(this),
34
+ this.obfuscateWithSeededBlockReversalV2.bind(this),
35
+ this.obfuscateWithSeededSubstitutionV2.bind(this),
36
+ ];
37
+
38
+ this.deobfuscationFunctionsV2 = [
39
+ this.deobfuscateByReversingV2.bind(this),
40
+ this.deobfuscateWithAtbashCipherV2.bind(this),
41
+ this.deobfuscateFromCharCodesV2.bind(this),
42
+ this.deobfuscateFromBinaryV2.bind(this),
43
+ this.deobfuscateWithCaesarCipherV2.bind(this),
44
+ this.deobfuscateBySwappingAdjacentBytesV2.bind(this),
45
+ this.deobfuscateByShufflingV2.bind(this),
46
+ this.deobfuscateWithXORV2.bind(this),
47
+ this.deobfuscateByDeinterleavingV2.bind(this),
48
+ this.deobfuscateWithVigenereCipherV2.bind(this),
49
+ this.deobfuscateWithSeededBlockReversalV2.bind(this),
50
+ this.deobfuscateWithSeededSubstitutionV2.bind(this),
51
+ ];
52
+ }
53
+
54
+ // --- V2 Encrypt/Decrypt High Level ---
55
+
56
+ /**
57
+ * Encrypts a mnemonic phrase using the Darkstar encryption scheme.
58
+ *
59
+ * @param {string} mnemonic - The mnemonic phrase to encrypt (space-separated words).
60
+ * @param {string} password - The password for encryption.
61
+ * @returns {Promise<{encryptedData: string, reverseKey: string}>} The encrypted result object.
62
+ */
63
+ async encrypt(mnemonic, password) {
64
+ const words = mnemonic.split(' ');
65
+ const obfuscatedWords = [];
66
+ const reverseKey = [];
67
+
68
+ const passwordBytes = this.stringToBytes(password);
69
+ const prngFactory = this.mulberry32.bind(this);
70
+
71
+ for (const word of words) {
72
+ let currentWordBytes = this.stringToBytes(word);
73
+
74
+ // Select functions
75
+ const selectedFunctions = Array.from({ length: 12 }, (_, i) => i);
76
+ this.shuffleArray(selectedFunctions, password + word, prngFactory);
77
+
78
+ const wordReverseKey = [];
79
+ const checksum = this._generateChecksum(selectedFunctions);
80
+ const checksumStr = checksum.toString();
81
+ const checksumBytes = this.stringToBytes(checksumStr);
82
+
83
+ const combinedSeed = new Uint8Array(passwordBytes.length + checksumBytes.length);
84
+ combinedSeed.set(passwordBytes);
85
+ combinedSeed.set(checksumBytes, passwordBytes.length);
86
+
87
+ for (const funcIndex of selectedFunctions) {
88
+ const func = this.obfuscationFunctionsV2[funcIndex];
89
+ const isSeeded = funcIndex >= 6;
90
+ const seed = isSeeded ? combinedSeed : undefined;
91
+
92
+ currentWordBytes = func(currentWordBytes, seed, prngFactory);
93
+ wordReverseKey.push(funcIndex);
94
+ }
95
+
96
+ obfuscatedWords.push(currentWordBytes);
97
+ reverseKey.push(wordReverseKey);
98
+ }
99
+
100
+ // Blob Construction
101
+ let totalLength = 0;
102
+ for (const wb of obfuscatedWords) {
103
+ totalLength += 2 + wb.length;
104
+ }
105
+ const finalBlob = new Uint8Array(totalLength);
106
+ let offset = 0;
107
+ for (const wb of obfuscatedWords) {
108
+ finalBlob[offset] = (wb.length >> 8) & 0xff;
109
+ finalBlob[offset + 1] = wb.length & 0xff;
110
+ finalBlob.set(wb, offset + 2);
111
+ offset += 2 + wb.length;
112
+ }
113
+
114
+ const binaryString = String.fromCharCode(...finalBlob); // Careful with stack size on huge blobs, but for phrases it's fine
115
+ const base64Content = btoa(binaryString);
116
+
117
+ const encryptedContent = await this.encryptAES256Async(base64Content, password, this.ITERATIONS_V2);
118
+
119
+ const resultObj = {
120
+ v: 2,
121
+ data: encryptedContent,
122
+ };
123
+
124
+ const reverseKeyString = JSON.stringify(reverseKey);
125
+ const encodedReverseKey = btoa(reverseKeyString);
126
+
127
+ return { encryptedData: JSON.stringify(resultObj), reverseKey: encodedReverseKey };
128
+ }
129
+
130
+ /**
131
+ * Decrypts the encrypted data back to the original mnemonic.
132
+ *
133
+ * @param {string} encryptedDataRaw - The JSON string containing the encrypted data object.
134
+ * @param {string} reverseKeyB64 - The Base64 encoded reverse key.
135
+ * @param {string} password - The password used for encryption.
136
+ * @returns {Promise<string>} The decrypted mnemonic phrase.
137
+ */
138
+ async decrypt(encryptedDataRaw, reverseKeyB64, password) {
139
+ let iterations = this.ITERATIONS_V2;
140
+ let encryptedContent = encryptedDataRaw;
141
+
142
+ // Check V2
143
+ try {
144
+ if (encryptedDataRaw.trim().startsWith('{')) {
145
+ const parsed = JSON.parse(encryptedDataRaw);
146
+ if (parsed.v === 2 && parsed.data) {
147
+ encryptedContent = parsed.data;
148
+ }
149
+ }
150
+ } catch (e) {}
151
+
152
+ // Decrypt AES
153
+ const decryptedObfuscatedString = await this.decryptAES256Async(encryptedContent, password, iterations);
154
+ if (!decryptedObfuscatedString) throw new Error("Decryption failed");
155
+
156
+ // Decrypt V2 Blob
157
+ const binaryString = atob(decryptedObfuscatedString);
158
+ const fullBlob = new Uint8Array(binaryString.length);
159
+ for(let i=0; i<binaryString.length; i++) fullBlob[i] = binaryString.charCodeAt(i);
160
+
161
+ // Decode Reverse Key
162
+ const reverseKeyString = atob(reverseKeyB64);
163
+ const reverseKeyJson = JSON.parse(reverseKeyString);
164
+
165
+ const deobfuscatedWords = [];
166
+ const passwordBytes = this.stringToBytes(password);
167
+ const prngFactory = this.mulberry32.bind(this);
168
+
169
+ let offset = 0;
170
+ let wordIndex = 0;
171
+
172
+ while (offset < fullBlob.length) {
173
+ if (wordIndex >= reverseKeyJson.length) break;
174
+
175
+ const len = (fullBlob[offset] << 8) | fullBlob[offset + 1];
176
+ offset += 2;
177
+
178
+ let currentWordBytes = fullBlob.slice(offset, offset + len);
179
+ offset += len;
180
+
181
+ const wordReverseKey = reverseKeyJson[wordIndex];
182
+
183
+ const checksum = this._generateChecksum(wordReverseKey);
184
+ const checksumStr = checksum.toString();
185
+ const checksumBytes = this.stringToBytes(checksumStr);
186
+ const combinedSeed = new Uint8Array(passwordBytes.length + checksumBytes.length);
187
+ combinedSeed.set(passwordBytes);
188
+ combinedSeed.set(checksumBytes, passwordBytes.length);
189
+
190
+ for (let j = wordReverseKey.length - 1; j >= 0; j--) {
191
+ const funcIndex = wordReverseKey[j];
192
+ const func = this.deobfuscationFunctionsV2[funcIndex];
193
+ const isSeeded = funcIndex >= 6;
194
+ const seed = isSeeded ? combinedSeed : undefined;
195
+
196
+ currentWordBytes = func(currentWordBytes, seed, prngFactory);
197
+ }
198
+
199
+ deobfuscatedWords.push(this.bytesToString(currentWordBytes));
200
+ wordIndex++;
201
+ }
202
+
203
+ return deobfuscatedWords.join(' ');
204
+ }
205
+
206
+ // --- AES Async (Using WebCrypto) ---
207
+
208
+ async encryptAES256Async(data, password, iterations) {
209
+ const enc = new TextEncoder();
210
+ const salt = crypto.getRandomValues(new Uint8Array(this.SALT_SIZE_BYTES));
211
+ const iv = crypto.getRandomValues(new Uint8Array(this.IV_SIZE_BYTES));
212
+
213
+ const keyMaterial = await crypto.subtle.importKey('raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey']);
214
+ const key = await crypto.subtle.deriveKey(
215
+ {
216
+ name: 'PBKDF2',
217
+ salt: salt,
218
+ iterations: iterations,
219
+ hash: 'SHA-256',
220
+ },
221
+ keyMaterial,
222
+ { name: 'AES-CBC', length: 256 },
223
+ false,
224
+ ['encrypt'],
225
+ );
226
+
227
+ const encrypted = await crypto.subtle.encrypt(
228
+ { name: 'AES-CBC', iv: iv },
229
+ key,
230
+ enc.encode(data),
231
+ );
232
+
233
+ const saltHex = this.buf2hex(salt);
234
+ const ivHex = this.buf2hex(iv);
235
+ const ciphertextBase64 = this.buf2base64(encrypted);
236
+
237
+ return saltHex + ivHex + ciphertextBase64;
238
+ }
239
+
240
+ async decryptAES256Async(transitmessage, password, iterations) {
241
+ try {
242
+ const saltHex = transitmessage.substr(0, 32);
243
+ const ivHex = transitmessage.substr(32, 32);
244
+ const encryptedBase64 = transitmessage.substring(64);
245
+
246
+ const salt = this.hex2buf(saltHex);
247
+ const iv = this.hex2buf(ivHex);
248
+ const encryptedBytes = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0));
249
+
250
+ const enc = new TextEncoder();
251
+ const keyMaterial = await crypto.subtle.importKey('raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey']);
252
+
253
+ const key = await crypto.subtle.deriveKey(
254
+ {
255
+ name: 'PBKDF2',
256
+ salt: salt,
257
+ iterations: iterations,
258
+ hash: 'SHA-256',
259
+ },
260
+ keyMaterial,
261
+ { name: 'AES-CBC', length: 256 },
262
+ false,
263
+ ['decrypt'],
264
+ );
265
+
266
+ const decrypted = await crypto.subtle.decrypt(
267
+ { name: 'AES-CBC', iv: iv },
268
+ key,
269
+ encryptedBytes,
270
+ );
271
+
272
+ return new TextDecoder().decode(decrypted);
273
+ } catch (error) {
274
+ console.error('Async Decryption failed:', error);
275
+ return '';
276
+ }
277
+ }
278
+
279
+ // --- Helpers ---
280
+ buf2hex(buffer) {
281
+ return Array.from(new Uint8Array(buffer))
282
+ .map((b) => b.toString(16).padStart(2, '0'))
283
+ .join('');
284
+ }
285
+
286
+ hex2buf(hex) {
287
+ return new Uint8Array(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
288
+ }
289
+
290
+ buf2base64(buffer) {
291
+ let binary = '';
292
+ const bytes = new Uint8Array(buffer);
293
+ const len = bytes.byteLength;
294
+ for (let i = 0; i < len; i++) {
295
+ binary += String.fromCharCode(bytes[i]);
296
+ }
297
+ return btoa(binary);
298
+ }
299
+
300
+ stringToBytes(str) {
301
+ return new TextEncoder().encode(str);
302
+ }
303
+
304
+ bytesToString(bytes) {
305
+ return new TextDecoder().decode(bytes);
306
+ }
307
+
308
+ _generateChecksum(numbers) {
309
+ if (!numbers || numbers.length === 0) return 0;
310
+ const sum = numbers.reduce((acc, curr) => acc + curr, 0);
311
+ return sum % 997;
312
+ }
313
+
314
+ // --- Obfuscation V2 ---
315
+
316
+ obfuscateByReversingV2(input) { return input.reverse(); }
317
+ deobfuscateByReversingV2(input) { return input.reverse(); }
318
+
319
+ obfuscateWithAtbashCipherV2(input) {
320
+ const output = new Uint8Array(input.length);
321
+ for(let i=0; i<input.length; i++) {
322
+ const code = input[i];
323
+ if (code >= 65 && code <= 90) output[i] = 90 - (code - 65);
324
+ else if (code >= 97 && code <= 122) output[i] = 122 - (code - 97);
325
+ else output[i] = code;
326
+ }
327
+ return output;
328
+ }
329
+ deobfuscateWithAtbashCipherV2(input) { return this.obfuscateWithAtbashCipherV2(input); }
330
+
331
+ obfuscateToCharCodesV2(input) {
332
+ const parts = [];
333
+ for(let i=0; i<input.length; i++) {
334
+ if(i>0) parts.push(44);
335
+ const strVal = input[i].toString();
336
+ for(let j=0; j<strVal.length; j++) parts.push(strVal.charCodeAt(j));
337
+ }
338
+ return new Uint8Array(parts);
339
+ }
340
+ deobfuscateFromCharCodesV2(input) {
341
+ const output = [];
342
+ let currentNumStr = '';
343
+ for(const byte of input) {
344
+ if(byte === 44) {
345
+ if(currentNumStr) {
346
+ output.push(parseInt(currentNumStr, 10));
347
+ currentNumStr = '';
348
+ }
349
+ } else {
350
+ currentNumStr += String.fromCharCode(byte);
351
+ }
352
+ }
353
+ if(currentNumStr) output.push(parseInt(currentNumStr, 10));
354
+ return new Uint8Array(output);
355
+ }
356
+
357
+ obfuscateToBinaryV2(input) {
358
+ const parts = [];
359
+ for(let i=0; i<input.length; i++) {
360
+ if(i>0) parts.push(44);
361
+ const val = input[i].toString(2);
362
+ for(let j=0; j<val.length; j++) parts.push(val.charCodeAt(j));
363
+ }
364
+ return new Uint8Array(parts);
365
+ }
366
+ deobfuscateFromBinaryV2(input) {
367
+ const output = [];
368
+ let currentVal = '';
369
+ for(const byte of input) {
370
+ if(byte === 44) {
371
+ if(currentVal) {
372
+ output.push(parseInt(currentVal, 2));
373
+ currentVal = '';
374
+ }
375
+ } else {
376
+ currentVal += String.fromCharCode(byte);
377
+ }
378
+ }
379
+ if(currentVal) output.push(parseInt(currentVal, 2));
380
+ return new Uint8Array(output);
381
+ }
382
+
383
+ obfuscateWithCaesarCipherV2(input) {
384
+ const output = new Uint8Array(input.length);
385
+ for(let i=0; i<input.length; i++) {
386
+ const code = input[i];
387
+ if(code >= 65 && code <= 90) output[i] = ((code - 65 + 13) % 26) + 65;
388
+ else if (code >= 97 && code <= 122) output[i] = ((code - 97 + 13) % 26) + 97;
389
+ else output[i] = code;
390
+ }
391
+ return output;
392
+ }
393
+ deobfuscateWithCaesarCipherV2(input) { return this.obfuscateWithCaesarCipherV2(input); }
394
+
395
+ obfuscateBySwappingAdjacentBytesV2(input) {
396
+ const output = new Uint8Array(input);
397
+ for(let i=0; i<output.length-1; i+=2) {
398
+ [output[i], output[i+1]] = [output[i+1], output[i]];
399
+ }
400
+ return output;
401
+ }
402
+ deobfuscateBySwappingAdjacentBytesV2(input) { return this.obfuscateBySwappingAdjacentBytesV2(input); }
403
+
404
+ // Seeded
405
+
406
+ obfuscateByShufflingV2(input, seed, prngFactory) {
407
+ const a = new Uint8Array(input);
408
+ const n = a.length;
409
+ const seedStr = this.bytesToString(seed);
410
+ const rng = prngFactory(seedStr);
411
+ for(let i=n-1; i>0; i--) {
412
+ const j = Math.floor(rng() * (i + 1));
413
+ [a[i], a[j]] = [a[j], a[i]];
414
+ }
415
+ return a;
416
+ }
417
+ deobfuscateByShufflingV2(input, seed, prngFactory) {
418
+ const a = new Uint8Array(input);
419
+ const n = a.length;
420
+ const indices = Array.from({length: n}, (_, i) => i);
421
+ const seedStr = this.bytesToString(seed);
422
+ const rng = prngFactory(seedStr);
423
+ for(let i=n-1; i>0; i--) {
424
+ const j = Math.floor(rng() * (i+1));
425
+ [indices[i], indices[j]] = [indices[j], indices[i]];
426
+ }
427
+ const unshuffled = new Uint8Array(n);
428
+ for(let i=0; i<n; i++) unshuffled[indices[i]] = a[i];
429
+ return unshuffled;
430
+ }
431
+
432
+ obfuscateWithXORV2(input, seed) {
433
+ const output = new Uint8Array(input.length);
434
+ for(let i=0; i<input.length; i++) output[i] = input[i] ^ seed[i % seed.length];
435
+ return output;
436
+ }
437
+ deobfuscateWithXORV2(input, seed) { return this.obfuscateWithXORV2(input, seed); }
438
+
439
+ obfuscateByInterleavingV2(input, seed, prngFactory) {
440
+ const randomChars = 'abcdefghijklmnopqrstuvwxyz0123456789';
441
+ const seedStr = this.bytesToString(seed);
442
+ const rng = prngFactory(seedStr);
443
+ const output = new Uint8Array(input.length * 2);
444
+ for(let i=0; i<input.length; i++) {
445
+ output[i*2] = input[i];
446
+ const randIdx = Math.floor(rng() * randomChars.length);
447
+ output[i*2+1] = randomChars.charCodeAt(randIdx);
448
+ }
449
+ return output;
450
+ }
451
+ deobfuscateByDeinterleavingV2(input) {
452
+ const output = new Uint8Array(input.length/2);
453
+ for(let i=0; i<input.length; i+=2) output[i/2] = input[i];
454
+ return output;
455
+ }
456
+
457
+ obfuscateWithVigenereCipherV2(input, seed) {
458
+ const parts = [];
459
+ for(let i=0; i<input.length; i++) {
460
+ if(i>0) parts.push(44);
461
+ const val = (input[i] + seed[i % seed.length]).toString();
462
+ for(let k=0; k<val.length; k++) parts.push(val.charCodeAt(k));
463
+ }
464
+ return new Uint8Array(parts);
465
+ }
466
+ deobfuscateWithVigenereCipherV2(input, seed) {
467
+ const output = [];
468
+ let currentValStr = '';
469
+ let byteIndex = 0;
470
+ for(const byte of input) {
471
+ if(byte === 44) {
472
+ if(currentValStr) {
473
+ const val = parseInt(currentValStr, 10);
474
+ const keyCode = seed[byteIndex % seed.length];
475
+ output.push(val - keyCode);
476
+ byteIndex++;
477
+ currentValStr = '';
478
+ }
479
+ } else {
480
+ currentValStr += String.fromCharCode(byte);
481
+ }
482
+ }
483
+ if(currentValStr) {
484
+ const val = parseInt(currentValStr, 10);
485
+ const keyCode = seed[byteIndex % seed.length];
486
+ output.push(val - keyCode);
487
+ }
488
+ return new Uint8Array(output);
489
+ }
490
+
491
+ obfuscateWithSeededBlockReversalV2(input, seed, prngFactory) {
492
+ const seedStr = this.bytesToString(seed);
493
+ const rng = prngFactory(seedStr);
494
+ const blockSize = Math.floor(rng() * (input.length / 2)) + 2;
495
+ const output = [];
496
+ for(let i=0; i<input.length; i+=blockSize) {
497
+ const chunk = input.slice(i, i+blockSize).reverse();
498
+ chunk.forEach(b => output.push(b));
499
+ }
500
+ return new Uint8Array(output);
501
+ }
502
+ deobfuscateWithSeededBlockReversalV2(input, seed, prngFactory) { return this.obfuscateWithSeededBlockReversalV2(input, seed, prngFactory); }
503
+
504
+ obfuscateWithSeededSubstitutionV2(input, seed, prngFactory) {
505
+ const chars = Array.from({length: 256}, (_, i) => i);
506
+ const seedStr = this.bytesToString(seed);
507
+ const rng = prngFactory(seedStr);
508
+ for(let i=255; i>0; i--) {
509
+ const j = Math.floor(rng() * (i+1));
510
+ [chars[i], chars[j]] = [chars[j], chars[i]];
511
+ }
512
+ const output = new Uint8Array(input.length);
513
+ for(let i=0; i<input.length; i++) output[i] = chars[input[i]];
514
+ return output;
515
+ }
516
+ deobfuscateWithSeededSubstitutionV2(input, seed, prngFactory) {
517
+ const chars = Array.from({length: 256}, (_, i) => i);
518
+ const seedStr = this.bytesToString(seed);
519
+ const rng = prngFactory(seedStr);
520
+ for(let i=255; i>0; i--) {
521
+ const j = Math.floor(rng() * (i+1));
522
+ [chars[i], chars[j]] = [chars[j], chars[i]];
523
+ }
524
+ const unsubMap = new Uint8Array(256);
525
+ for(let i=0; i<256; i++) unsubMap[chars[i]] = i;
526
+ const output = new Uint8Array(input.length);
527
+ for(let i=0; i<input.length; i++) output[i] = unsubMap[input[i]];
528
+ return output;
529
+ }
530
+
531
+ // --- PRNG ---
532
+
533
+ shuffleArray(array, seed, prngFactory) {
534
+ const rng = prngFactory(seed);
535
+ for (let i = array.length - 1; i > 0; i--) {
536
+ const j = Math.floor(rng() * (i + 1));
537
+ [array[i], array[j]] = [array[j], array[i]];
538
+ }
539
+ }
540
+
541
+ mulberry32(seed) {
542
+ let h = 0;
543
+ for (let i = 0; i < seed.length; i++) {
544
+ h = Math.imul(h ^ seed.charCodeAt(i), 3432918353);
545
+ h = (h << 13) | (h >>> 19);
546
+ }
547
+ h = Math.imul(h ^ (h >>> 16), 2246822507);
548
+ h = Math.imul(h ^ (h >>> 13), 3266489909);
549
+ h ^= h >>> 16;
550
+ let state = h;
551
+
552
+ return function () {
553
+ state = (state + 0x6d2b79f5) | 0;
554
+ let t = Math.imul(state ^ (state >>> 15), 1 | state);
555
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
556
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
557
+ };
558
+ }
559
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@kryklin/darkstar-crypt-node",
3
+ "version": "1.0.0",
4
+ "description": "Standalone Node.js implementation of Darkstar Encryption",
5
+ "main": "darkstar_crypt.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "darkstar-crypt": "darkstar_crypt.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node test.js"
12
+ },
13
+ "keywords": [
14
+ "darkstar",
15
+ "encryption",
16
+ "cryptography",
17
+ "aes",
18
+ "cli"
19
+ ],
20
+ "author": "Victor Kane",
21
+ "license": "MIT",
22
+ "dependencies": {}
23
+ }