@jscrypto/classic 0.1.0 → 0.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.
Files changed (40) hide show
  1. package/README.md +21 -3
  2. package/dist/ciphers/aes.js +1 -1
  3. package/dist/ciphers/aes.js.map +1 -1
  4. package/dist/ciphers/rc4.js +2 -2
  5. package/dist/ciphers/rc4.js.map +1 -1
  6. package/dist/ciphers/triple-des.js +1 -1
  7. package/dist/ciphers/triple-des.js.map +1 -1
  8. package/dist/index.cjs +330 -49
  9. package/dist/index.cjs.map +3 -3
  10. package/dist/index.mjs +312 -27
  11. package/dist/index.mjs.map +3 -3
  12. package/dist/jscrypto-classic.iife.js +415 -84
  13. package/dist/jscrypto-classic.iife.js.map +3 -3
  14. package/dist/jscrypto-classic.iife.min.js +2 -2
  15. package/dist/jscrypto-classic.iife.min.js.map +3 -3
  16. package/dist/jscrypto-classic.umd.js +415 -84
  17. package/dist/jscrypto-classic.umd.js.map +3 -3
  18. package/dist/jscrypto-classic.umd.min.js +2 -2
  19. package/dist/jscrypto-classic.umd.min.js.map +3 -3
  20. package/dist/kdfs/evpkdf.js +3 -2
  21. package/dist/kdfs/evpkdf.js.map +1 -1
  22. package/dist/kdfs/pbkdf2.js +1 -1
  23. package/dist/kdfs/pbkdf2.js.map +1 -1
  24. package/dist/modes/cbc.js +4 -4
  25. package/dist/modes/cbc.js.map +1 -1
  26. package/dist/modes/cfb.js +2 -2
  27. package/dist/modes/cfb.js.map +1 -1
  28. package/dist/modes/ctr.js +2 -2
  29. package/dist/modes/ctr.js.map +1 -1
  30. package/dist/modes/ecb.js +4 -4
  31. package/dist/modes/ecb.js.map +1 -1
  32. package/dist/modes/gcm.d.ts +1 -1
  33. package/dist/modes/gcm.d.ts.map +1 -1
  34. package/dist/modes/gcm.js +289 -4
  35. package/dist/modes/gcm.js.map +1 -1
  36. package/dist/modes/ofb.js +2 -2
  37. package/dist/modes/ofb.js.map +1 -1
  38. package/dist/paddings/iso10126.js +2 -1
  39. package/dist/paddings/iso10126.js.map +1 -1
  40. package/package.json +11 -2
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @jscrypto/classic v0.1.0
2
+ * @jscrypto/classic v0.2.0
3
3
  * Copyright 2026 Chen, Yi-Cyuan
4
4
  * Released under the MIT license
5
5
  */
@@ -65,7 +65,7 @@ var aes = {
65
65
  }
66
66
  };
67
67
  function createAesCipher(key) {
68
- if (![16, 24, 32].includes(key.length)) {
68
+ if (key.length !== 16 && key.length !== 24 && key.length !== 32) {
69
69
  throw new Error("AES key must be 128, 192, or 256 bits.");
70
70
  }
71
71
  return createCryptoJsBlockCipher({
@@ -142,10 +142,10 @@ function createRc4Transform(key, drop = 0) {
142
142
  assertNotFinalized(finalized);
143
143
  return processInput(input);
144
144
  },
145
- finalize(input = new Uint8Array()) {
145
+ finalize(input = new Uint8Array(0)) {
146
146
  assertNotFinalized(finalized);
147
147
  finalized = true;
148
- return input.length === 0 ? new Uint8Array() : processInput(input);
148
+ return input.length === 0 ? new Uint8Array(0) : processInput(input);
149
149
  }
150
150
  };
151
151
  }
@@ -210,7 +210,7 @@ var tripleDes = {
210
210
  }
211
211
  };
212
212
  function createTripleDesCipher(key) {
213
- if (![16, 24].includes(key.length)) {
213
+ if (key.length !== 16 && key.length !== 24) {
214
214
  throw new Error("Triple DES key must be 128 or 192 bits.");
215
215
  }
216
216
  return createCryptoJsBlockCipher({
@@ -272,13 +272,14 @@ var evpKdf = {
272
272
  }
273
273
  };
274
274
  function deriveEvpKdf(params) {
275
+ var _a;
275
276
  assertPositiveInteger(params.length, "EvpKDF length");
276
277
  if (params.iterations !== void 0) {
277
278
  assertPositiveInteger(params.iterations, "EvpKDF iterations");
278
279
  }
279
280
  const options = {
280
281
  keySize: params.length / 4,
281
- iterations: params.iterations ?? 1
282
+ iterations: (_a = params.iterations) != null ? _a : 1
282
283
  };
283
284
  const hasher = getHasher(params.hash);
284
285
  if (hasher) {
@@ -301,7 +302,7 @@ function getHasher(hash) {
301
302
  return hasher;
302
303
  }
303
304
  function normalizeHashName(hash) {
304
- return hash.replaceAll("-", "").toUpperCase();
305
+ return hash.replace(/-/g, "").toUpperCase();
305
306
  }
306
307
  function assertPositiveInteger(value, label) {
307
308
  if (!Number.isInteger(value) || value <= 0) {
@@ -345,7 +346,7 @@ function getHasher2(hash) {
345
346
  return hasher;
346
347
  }
347
348
  function normalizeHashName2(hash) {
348
- return hash.replaceAll("-", "").toUpperCase();
349
+ return hash.replace(/-/g, "").toUpperCase();
349
350
  }
350
351
  function assertPositiveInteger2(value, label) {
351
352
  if (!Number.isInteger(value) || value <= 0) {
@@ -386,8 +387,8 @@ function createCbcEncryptor(cipher, iv) {
386
387
  }
387
388
  return output;
388
389
  },
389
- finalize(input = new Uint8Array()) {
390
- return input.length === 0 ? new Uint8Array() : this.process(input);
390
+ finalize(input = new Uint8Array(0)) {
391
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
391
392
  }
392
393
  };
393
394
  }
@@ -405,8 +406,8 @@ function createCbcDecryptor(cipher, iv) {
405
406
  }
406
407
  return output;
407
408
  },
408
- finalize(input = new Uint8Array()) {
409
- return input.length === 0 ? new Uint8Array() : this.process(input);
409
+ finalize(input = new Uint8Array(0)) {
410
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
410
411
  }
411
412
  };
412
413
  }
@@ -460,8 +461,8 @@ function createCfbTransform(cipher, iv, encrypting) {
460
461
  }
461
462
  return output;
462
463
  },
463
- finalize(input = new Uint8Array()) {
464
- return input.length === 0 ? new Uint8Array() : this.process(input);
464
+ finalize(input = new Uint8Array(0)) {
465
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
465
466
  }
466
467
  };
467
468
  }
@@ -499,8 +500,8 @@ function createCtrTransform(cipher, iv) {
499
500
  }
500
501
  return output;
501
502
  },
502
- finalize(input = new Uint8Array()) {
503
- return input.length === 0 ? new Uint8Array() : this.process(input);
503
+ finalize(input = new Uint8Array(0)) {
504
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
504
505
  }
505
506
  };
506
507
  }
@@ -536,8 +537,8 @@ function createEcbEncryptor(cipher) {
536
537
  }
537
538
  return output;
538
539
  },
539
- finalize(input = new Uint8Array()) {
540
- return input.length === 0 ? new Uint8Array() : this.process(input);
540
+ finalize(input = new Uint8Array(0)) {
541
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
541
542
  }
542
543
  };
543
544
  }
@@ -551,8 +552,8 @@ function createEcbDecryptor(cipher) {
551
552
  }
552
553
  return output;
553
554
  },
554
- finalize(input = new Uint8Array()) {
555
- return input.length === 0 ? new Uint8Array() : this.process(input);
555
+ finalize(input = new Uint8Array(0)) {
556
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
556
557
  }
557
558
  };
558
559
  }
@@ -561,19 +562,302 @@ function assertBlockMultiple2(blockSize, input) {
561
562
  }
562
563
 
563
564
  // packages/classic/src/modes/gcm.ts
565
+ import {
566
+ assertBytes,
567
+ concatBytes as concatBytes2,
568
+ equalBytes as equalBytes2
569
+ } from "@jscrypto/core";
564
570
  var gcm = {
565
571
  kind: "mode",
566
572
  name: "GCM",
567
573
  aead: true,
568
574
  requiredBlockSize: 16,
569
575
  requiresPadding: false,
570
- createEncryptor() {
571
- throw new Error("GCM mode is not implemented yet.");
576
+ createEncryptor({ cipher, iv, options }) {
577
+ return createGcmEncryptor(cipher, getNonce(iv, options), getAad(options), getTagLength(options));
572
578
  },
573
- createDecryptor() {
574
- throw new Error("GCM mode is not implemented yet.");
579
+ createDecryptor({ cipher, iv, options }) {
580
+ return createGcmDecryptor(cipher, getNonce(iv, options), getAad(options), getTagLength(options), getTag(options));
575
581
  }
576
582
  };
583
+ var BLOCK_SIZE = 16;
584
+ var DEFAULT_TAG_LENGTH = 16;
585
+ var R_WORD = 3774873600;
586
+ function createGcmEncryptor(cipher, nonce, aad, tagLength) {
587
+ assertGcmCipher(cipher);
588
+ const auth = createGhash(cipher.encryptBlock(new Uint8Array(BLOCK_SIZE)));
589
+ auth.update(aad);
590
+ auth.pad();
591
+ const j0 = createInitialCounter(auth.h, nonce);
592
+ const tagMask = cipher.encryptBlock(j0);
593
+ const counter = j0.slice();
594
+ incrementCounter2(counter);
595
+ const xor = createCounterXor(cipher, counter);
596
+ let ciphertextLength = 0;
597
+ return {
598
+ process(input) {
599
+ const ciphertext = xor(input);
600
+ auth.update(ciphertext);
601
+ ciphertextLength += ciphertext.length;
602
+ return ciphertext;
603
+ },
604
+ finalize(input = new Uint8Array(0)) {
605
+ const ciphertext = input.length === 0 ? new Uint8Array(0) : this.process(input);
606
+ const tag = createTag(auth, tagMask, aad.length, ciphertextLength, tagLength);
607
+ return concatBytes2(ciphertext, tag);
608
+ }
609
+ };
610
+ }
611
+ function createGcmDecryptor(cipher, nonce, aad, tagLength, detachedTag) {
612
+ assertGcmCipher(cipher);
613
+ const h = cipher.encryptBlock(new Uint8Array(BLOCK_SIZE));
614
+ const j0 = createInitialCounter(h, nonce);
615
+ const tagMask = cipher.encryptBlock(j0);
616
+ let pending = new Uint8Array(0);
617
+ return {
618
+ process(input) {
619
+ pending = concatBytes2(pending, input);
620
+ return new Uint8Array(0);
621
+ },
622
+ finalize(input = new Uint8Array(0)) {
623
+ if (input.length !== 0) {
624
+ this.process(input);
625
+ }
626
+ let ciphertext = pending;
627
+ let tag = detachedTag;
628
+ if (!tag) {
629
+ if (pending.length < tagLength) {
630
+ throw new Error("GCM ciphertext must include an authentication tag.");
631
+ }
632
+ ciphertext = new Uint8Array(pending.subarray(0, pending.length - tagLength));
633
+ tag = new Uint8Array(pending.subarray(pending.length - tagLength));
634
+ }
635
+ const auth = createGhash(h);
636
+ auth.update(aad);
637
+ auth.pad();
638
+ auth.update(ciphertext);
639
+ const expectedTag = createTag(auth, tagMask, aad.length, ciphertext.length, tagLength);
640
+ if (!equalBytes2(expectedTag, tag)) {
641
+ throw new Error("GCM authentication failed.");
642
+ }
643
+ const counter = j0.slice();
644
+ incrementCounter2(counter);
645
+ const plaintext = createCounterXor(cipher, counter)(ciphertext);
646
+ pending = new Uint8Array(0);
647
+ return plaintext;
648
+ }
649
+ };
650
+ }
651
+ function createGhash(h) {
652
+ const hValue = blockToWords(h);
653
+ let state = createZeroWords();
654
+ let pending = new Uint8Array(0);
655
+ function updateBlock(block) {
656
+ state = multiplyGf128(xorWords(state, blockToWords(padBlock(block))), hValue);
657
+ }
658
+ return {
659
+ h,
660
+ update(input) {
661
+ const data = concatBytes2(pending, input);
662
+ const processLength = data.length - data.length % BLOCK_SIZE;
663
+ for (let offset = 0; offset < processLength; offset += BLOCK_SIZE) {
664
+ updateBlock(data.subarray(offset, offset + BLOCK_SIZE));
665
+ }
666
+ pending = data.slice(processLength);
667
+ },
668
+ pad() {
669
+ if (pending.length !== 0) {
670
+ updateBlock(pending);
671
+ pending = new Uint8Array(0);
672
+ }
673
+ },
674
+ digest(aadLength, ciphertextLength) {
675
+ this.pad();
676
+ updateBlock(createLengthBlock(aadLength, ciphertextLength));
677
+ return wordsToBlock(state);
678
+ }
679
+ };
680
+ }
681
+ function createInitialCounter(h, nonce) {
682
+ if (nonce.length === 0) {
683
+ throw new Error("GCM mode requires a nonce.");
684
+ }
685
+ if (nonce.length === 12) {
686
+ const j0 = new Uint8Array(BLOCK_SIZE);
687
+ j0.set(nonce);
688
+ j0[15] = 1;
689
+ return j0;
690
+ }
691
+ const auth = createGhash(h);
692
+ auth.update(nonce);
693
+ return auth.digest(0, nonce.length);
694
+ }
695
+ function createCounterXor(cipher, counter) {
696
+ let keystream = new Uint8Array(0);
697
+ let position = BLOCK_SIZE;
698
+ return (input) => {
699
+ const output = new Uint8Array(input.length);
700
+ for (let i = 0; i < input.length; i++) {
701
+ if (position === BLOCK_SIZE) {
702
+ keystream = cipher.encryptBlock(counter);
703
+ incrementCounter2(counter);
704
+ position = 0;
705
+ }
706
+ output[i] = input[i] ^ keystream[position];
707
+ position++;
708
+ }
709
+ return output;
710
+ };
711
+ }
712
+ function createTag(auth, tagMask, aadLength, ciphertextLength, tagLength) {
713
+ const tag = auth.digest(aadLength, ciphertextLength);
714
+ for (let i = 0; i < tag.length; i++) {
715
+ tag[i] ^= tagMask[i];
716
+ }
717
+ return tag.subarray(0, tagLength);
718
+ }
719
+ function createZeroWords() {
720
+ return [0, 0, 0, 0];
721
+ }
722
+ function multiplyGf128(x, y) {
723
+ const z = createZeroWords();
724
+ const v = [y[0], y[1], y[2], y[3]];
725
+ for (let i = 0; i < 128; i++) {
726
+ if ((x[i >>> 5] & 2147483648 >>> (i & 31)) !== 0) {
727
+ xorWordsInPlace(z, v);
728
+ }
729
+ shiftRightAndReduce(v);
730
+ }
731
+ return z;
732
+ }
733
+ function shiftRightAndReduce(words) {
734
+ const lsb = words[3] & 1;
735
+ words[3] = (words[3] >>> 1 | (words[2] & 1) << 31) >>> 0;
736
+ words[2] = (words[2] >>> 1 | (words[1] & 1) << 31) >>> 0;
737
+ words[1] = (words[1] >>> 1 | (words[0] & 1) << 31) >>> 0;
738
+ words[0] >>>= 1;
739
+ if (lsb) {
740
+ words[0] = (words[0] ^ R_WORD) >>> 0;
741
+ }
742
+ }
743
+ function xorWords(left, right) {
744
+ return [
745
+ (left[0] ^ right[0]) >>> 0,
746
+ (left[1] ^ right[1]) >>> 0,
747
+ (left[2] ^ right[2]) >>> 0,
748
+ (left[3] ^ right[3]) >>> 0
749
+ ];
750
+ }
751
+ function xorWordsInPlace(left, right) {
752
+ left[0] = (left[0] ^ right[0]) >>> 0;
753
+ left[1] = (left[1] ^ right[1]) >>> 0;
754
+ left[2] = (left[2] ^ right[2]) >>> 0;
755
+ left[3] = (left[3] ^ right[3]) >>> 0;
756
+ }
757
+ function incrementCounter2(counter) {
758
+ const value = (counter[12] << 24 >>> 0 | counter[13] << 16 | counter[14] << 8 | counter[15]) + 1 >>> 0;
759
+ counter[12] = value >>> 24;
760
+ counter[13] = value >>> 16;
761
+ counter[14] = value >>> 8;
762
+ counter[15] = value;
763
+ }
764
+ function padBlock(input) {
765
+ if (input.length === BLOCK_SIZE) {
766
+ return input;
767
+ }
768
+ const output = new Uint8Array(BLOCK_SIZE);
769
+ output.set(input);
770
+ return output;
771
+ }
772
+ function createLengthBlock(aadLength, ciphertextLength) {
773
+ const output = new Uint8Array(BLOCK_SIZE);
774
+ writeBitLength64BE(aadLength, output, 0);
775
+ writeBitLength64BE(ciphertextLength, output, 8);
776
+ return output;
777
+ }
778
+ function writeBitLength64BE(byteLength, output, offset) {
779
+ const high = Math.floor(byteLength / 536870912);
780
+ const low = byteLength % 536870912 * 8;
781
+ writeUint32BE(high, output, offset);
782
+ writeUint32BE(low, output, offset + 4);
783
+ }
784
+ function blockToWords(input) {
785
+ return [
786
+ readUint32BE(input, 0),
787
+ readUint32BE(input, 4),
788
+ readUint32BE(input, 8),
789
+ readUint32BE(input, 12)
790
+ ];
791
+ }
792
+ function wordsToBlock(words) {
793
+ const output = new Uint8Array(BLOCK_SIZE);
794
+ writeUint32BE(words[0], output, 0);
795
+ writeUint32BE(words[1], output, 4);
796
+ writeUint32BE(words[2], output, 8);
797
+ writeUint32BE(words[3], output, 12);
798
+ return output;
799
+ }
800
+ function readUint32BE(input, offset) {
801
+ return (input[offset] << 24 >>> 0 | input[offset + 1] << 16 | input[offset + 2] << 8 | input[offset + 3]) >>> 0;
802
+ }
803
+ function writeUint32BE(value, output, offset) {
804
+ output[offset] = value >>> 24;
805
+ output[offset + 1] = value >>> 16;
806
+ output[offset + 2] = value >>> 8;
807
+ output[offset + 3] = value;
808
+ }
809
+ function getNonce(iv, options) {
810
+ const nonce = getOptions(options).nonce;
811
+ if (nonce !== void 0) {
812
+ assertBytes(nonce, "GCM nonce");
813
+ if (iv !== void 0) {
814
+ throw new Error("GCM mode accepts either iv or nonce, not both.");
815
+ }
816
+ return nonce;
817
+ }
818
+ if (!iv) {
819
+ throw new Error("GCM mode requires an IV/nonce.");
820
+ }
821
+ return iv;
822
+ }
823
+ function getAad(options) {
824
+ const aad = getOptions(options).aad;
825
+ if (aad === void 0) {
826
+ return new Uint8Array(0);
827
+ }
828
+ assertBytes(aad, "GCM aad");
829
+ return aad;
830
+ }
831
+ function getTag(options) {
832
+ const tag = getOptions(options).tag;
833
+ if (tag === void 0) {
834
+ return void 0;
835
+ }
836
+ assertBytes(tag, "GCM tag");
837
+ return tag;
838
+ }
839
+ function getTagLength(options) {
840
+ const tag = getTag(options);
841
+ if (tag) {
842
+ return tag.length;
843
+ }
844
+ const tagLength = getOptions(options).tagLength;
845
+ if (tagLength === void 0) {
846
+ return DEFAULT_TAG_LENGTH;
847
+ }
848
+ if (typeof tagLength !== "number" || !Number.isInteger(tagLength) || tagLength < 4 || tagLength > BLOCK_SIZE) {
849
+ throw new RangeError("GCM tagLength must be an integer between 4 and 16 bytes.");
850
+ }
851
+ return tagLength;
852
+ }
853
+ function getOptions(options) {
854
+ return typeof options === "object" && options !== null ? options : {};
855
+ }
856
+ function assertGcmCipher(cipher) {
857
+ if (cipher.blockSize !== BLOCK_SIZE) {
858
+ throw new Error("GCM mode requires a 128-bit block cipher.");
859
+ }
860
+ }
577
861
 
578
862
  // packages/classic/src/modes/ofb.ts
579
863
  import { assertIv as assertIv4 } from "@jscrypto/core";
@@ -608,8 +892,8 @@ function createOfbTransform(cipher, iv) {
608
892
  }
609
893
  return output;
610
894
  },
611
- finalize(input = new Uint8Array()) {
612
- return input.length === 0 ? new Uint8Array() : this.process(input);
895
+ finalize(input = new Uint8Array(0)) {
896
+ return input.length === 0 ? new Uint8Array(0) : this.process(input);
613
897
  }
614
898
  };
615
899
  }
@@ -692,11 +976,12 @@ function getPaddingLength2(inputLength, blockSize) {
692
976
  return getBlockPaddingLength2(inputLength, blockSize);
693
977
  }
694
978
  function fillRandom(bytes) {
979
+ var _a;
695
980
  if (bytes.length === 0) {
696
981
  return;
697
982
  }
698
983
  const crypto = globalThis;
699
- crypto.crypto?.getRandomValues(bytes);
984
+ (_a = crypto.crypto) == null ? void 0 : _a.getRandomValues(bytes);
700
985
  if (bytes.some((byte) => byte !== 0)) {
701
986
  return;
702
987
  }