@kryklin/darkstar-crypt-node 1.0.1 → 1.0.3

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 +117 -5
  2. package/package.json +1 -1
package/darkstar_crypt.js CHANGED
@@ -121,8 +121,8 @@ export class DarkstarCrypt {
121
121
  data: encryptedContent,
122
122
  };
123
123
 
124
- const reverseKeyString = JSON.stringify(reverseKey);
125
- const encodedReverseKey = btoa(reverseKeyString);
124
+ // Compress the reverse key using binary packing (4 bits per value)
125
+ const encodedReverseKey = this.packReverseKey(reverseKey);
126
126
 
127
127
  return { encryptedData: JSON.stringify(resultObj), reverseKey: encodedReverseKey };
128
128
  }
@@ -159,8 +159,19 @@ export class DarkstarCrypt {
159
159
  for(let i=0; i<binaryString.length; i++) fullBlob[i] = binaryString.charCodeAt(i);
160
160
 
161
161
  // Decode Reverse Key
162
- const reverseKeyString = atob(reverseKeyB64);
163
- const reverseKeyJson = JSON.parse(reverseKeyString);
162
+ let reverseKeyJson;
163
+ try {
164
+ // Try to detect Legacy/V2 JSON key format
165
+ const reversedKeyString = atob(reverseKeyB64);
166
+ if (reversedKeyString.trim().startsWith('[')) {
167
+ reverseKeyJson = JSON.parse(reversedKeyString);
168
+ } else {
169
+ reverseKeyJson = this.unpackReverseKey(reverseKeyB64);
170
+ }
171
+ } catch (e) {
172
+ // Fallback
173
+ reverseKeyJson = this.unpackReverseKey(reverseKeyB64);
174
+ }
164
175
 
165
176
  const deobfuscatedWords = [];
166
177
  const passwordBytes = this.stringToBytes(password);
@@ -233,7 +244,7 @@ export class DarkstarCrypt {
233
244
  const saltHex = this.buf2hex(salt);
234
245
  const ivHex = this.buf2hex(iv);
235
246
  const ciphertextBase64 = this.buf2base64(encrypted);
236
-
247
+
237
248
  return saltHex + ivHex + ciphertextBase64;
238
249
  }
239
250
 
@@ -297,6 +308,57 @@ export class DarkstarCrypt {
297
308
  return btoa(binary);
298
309
  }
299
310
 
311
+ // --- Compression Helpers ---
312
+
313
+ packReverseKey(reverseKey) {
314
+ const wordCount = reverseKey.length;
315
+ // 12 numbers per word, 4 bits each -> 6 bytes
316
+ const packedSize = wordCount * 6;
317
+ const buffer = new Uint8Array(packedSize);
318
+
319
+ let offset = 0;
320
+ for (const wordKey of reverseKey) {
321
+ if (wordKey.length !== 12) throw new Error("Cannot compress non-standard reverse key length.");
322
+
323
+ for (let i = 0; i < 12; i += 2) {
324
+ const high = wordKey[i]; // 0-11
325
+ const low = wordKey[i+1]; // 0-11
326
+ // Pack into one byte
327
+ buffer[offset++] = (high << 4) | (low & 0x0F);
328
+ }
329
+ }
330
+ return this.buf2base64(buffer);
331
+ }
332
+
333
+ unpackReverseKey(base64) {
334
+ // Decode base64 to bytes
335
+ const binary = atob(base64);
336
+ const buffer = new Uint8Array(binary.length);
337
+ for (let i = 0; i < binary.length; i++) {
338
+ buffer[i] = binary.charCodeAt(i);
339
+ }
340
+
341
+ // Unpack
342
+ const reverseKey = [];
343
+ // 6 bytes per word
344
+ const wordCount = buffer.length / 6;
345
+
346
+ let offset = 0;
347
+ for (let w = 0; w < wordCount; w++) {
348
+ const wordKey = [];
349
+ for (let i = 0; i < 6; i++) {
350
+ const byte = buffer[offset++];
351
+ const high = (byte >> 4) & 0x0F;
352
+ const low = byte & 0x0F;
353
+ wordKey.push(high);
354
+ wordKey.push(low);
355
+ }
356
+ reverseKey.push(wordKey);
357
+ }
358
+
359
+ return reverseKey;
360
+ }
361
+
300
362
  stringToBytes(str) {
301
363
  return new TextEncoder().encode(str);
302
364
  }
@@ -557,3 +619,53 @@ export class DarkstarCrypt {
557
619
  };
558
620
  }
559
621
  }
622
+
623
+ // --- CLI Support ---
624
+
625
+ import { fileURLToPath } from 'node:url';
626
+ import { resolve } from 'node:path';
627
+
628
+ const __filename = fileURLToPath(import.meta.url);
629
+ const isMain = process.argv[1] && resolve(process.argv[1]) === resolve(__filename);
630
+
631
+ if (isMain) {
632
+ const args = process.argv.slice(2);
633
+ const command = args[0];
634
+ const crypt = new DarkstarCrypt();
635
+
636
+ if (command === 'encrypt') {
637
+ const mnemonic = args[1];
638
+ const password = args[2];
639
+ crypt.encrypt(mnemonic, password).then(res => {
640
+ console.log(JSON.stringify(res));
641
+ }).catch(err => {
642
+ console.error(err);
643
+ process.exit(1);
644
+ });
645
+ } else if (command === 'decrypt') {
646
+ const data = args[1];
647
+ const rk = args[2];
648
+ const password = args[3];
649
+ crypt.decrypt(data, rk, password).then(res => {
650
+ console.log(res);
651
+ }).catch(err => {
652
+ console.error(err);
653
+ process.exit(1);
654
+ });
655
+ } else if (command === 'test') {
656
+ const mnemonic = "cat dog fish bird";
657
+ const password = "MySecre!Password123";
658
+ crypt.encrypt(mnemonic, password).then(res => {
659
+ return crypt.decrypt(res.encryptedData, res.reverseKey, password);
660
+ }).then(decrypted => {
661
+ if (decrypted === "cat dog fish bird") {
662
+ console.log("Test Passed!");
663
+ } else {
664
+ console.error("Test Failed!");
665
+ process.exit(1);
666
+ }
667
+ });
668
+ } else {
669
+ console.log("Usage: node darkstar_crypt.js <encrypt|decrypt|test> ...");
670
+ }
671
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kryklin/darkstar-crypt-node",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Standalone Node.js implementation of Darkstar Encryption",
5
5
  "main": "darkstar_crypt.js",
6
6
  "type": "module",