@ivujs/i-utils 2.0.0 → 2.1.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 (214) hide show
  1. package/README.md +40 -42
  2. package/dist/cjs/ID-card/index.cjs +21 -13
  3. package/dist/cjs/array/index.cjs +40 -34
  4. package/dist/cjs/clipboard/index.cjs +14 -10
  5. package/dist/cjs/color/index.cjs +73 -59
  6. package/dist/cjs/cookie/index.cjs +16 -13
  7. package/dist/cjs/crypto/base64/base64.cjs +398 -206
  8. package/dist/cjs/crypto/base64/index.cjs +58 -35
  9. package/dist/cjs/crypto/md5/index.cjs +33 -8
  10. package/dist/cjs/crypto/md5/md5.cjs +298 -844
  11. package/dist/cjs/crypto/sha256/index.cjs +95 -0
  12. package/dist/cjs/crypto/sha256/sha256.cjs +557 -0
  13. package/dist/cjs/crypto/sm3/index.cjs +27 -0
  14. package/dist/cjs/crypto/sm3/sm3.cjs +200 -0
  15. package/dist/cjs/crypto/sm4/index.cjs +101 -0
  16. package/dist/cjs/crypto/sm4/sm4.cjs +498 -0
  17. package/dist/cjs/date/index.cjs +379 -335
  18. package/dist/cjs/desensitized/index.cjs +21 -18
  19. package/dist/cjs/device/index.cjs +33 -30
  20. package/dist/cjs/dom/index.cjs +26 -23
  21. package/dist/cjs/file/index.cjs +51 -41
  22. package/dist/cjs/function/index.cjs +22 -19
  23. package/dist/cjs/id/index.cjs +6 -2
  24. package/dist/cjs/index.cjs +108 -127
  25. package/dist/cjs/keycode/index.cjs +9 -12
  26. package/dist/cjs/math/index.cjs +113 -81
  27. package/dist/cjs/number/index.cjs +10 -7
  28. package/dist/cjs/object/index.cjs +77 -30
  29. package/dist/cjs/pagination/index.cjs +25 -10
  30. package/dist/cjs/random/index.cjs +8 -5
  31. package/dist/cjs/regexp/index.cjs +23 -20
  32. package/dist/cjs/storage/index.cjs +4 -1
  33. package/dist/cjs/storage/localStorage.cjs +5 -5
  34. package/dist/cjs/storage/sessionStorage.cjs +6 -6
  35. package/dist/cjs/string/index.cjs +66 -63
  36. package/dist/cjs/url/index.cjs +83 -80
  37. package/dist/cjs/validate/index.cjs +122 -106
  38. package/dist/es/ID-card/index.d.ts +19 -14
  39. package/dist/es/ID-card/index.mjs +22 -14
  40. package/dist/es/array/index.d.ts +56 -50
  41. package/dist/es/array/index.mjs +40 -34
  42. package/dist/es/clipboard/index.d.ts +10 -7
  43. package/dist/es/clipboard/index.mjs +14 -10
  44. package/dist/es/color/index.d.ts +28 -25
  45. package/dist/es/color/index.mjs +73 -59
  46. package/dist/es/constants/date.d.ts +4 -174
  47. package/dist/es/constants/id-card.d.ts +4 -43
  48. package/dist/es/constants/index.d.ts +11 -7
  49. package/dist/es/constants/keycode.d.ts +1 -103
  50. package/dist/es/constants/lang.d.ts +4 -4
  51. package/dist/es/constants/math.d.ts +4 -4
  52. package/dist/es/constants/regexp.d.ts +4 -24
  53. package/dist/es/constants/sort.d.ts +4 -5
  54. package/dist/es/cookie/index.d.ts +13 -13
  55. package/dist/es/cookie/index.mjs +16 -13
  56. package/dist/es/crypto/base64/base64.d.ts +8 -5
  57. package/dist/es/crypto/base64/base64.mjs +393 -204
  58. package/dist/es/crypto/base64/index.d.ts +41 -24
  59. package/dist/es/crypto/base64/index.mjs +53 -32
  60. package/dist/es/crypto/index.d.ts +8 -8
  61. package/dist/es/crypto/md5/index.d.ts +20 -7
  62. package/dist/es/crypto/md5/index.mjs +32 -9
  63. package/dist/es/crypto/md5/md5.d.ts +9 -142
  64. package/dist/es/crypto/md5/md5.mjs +299 -844
  65. package/dist/es/crypto/sha256/index.d.ts +52 -0
  66. package/dist/es/crypto/sha256/index.mjs +86 -0
  67. package/dist/es/crypto/sha256/sha256.d.ts +82 -0
  68. package/dist/es/crypto/sha256/sha256.mjs +548 -0
  69. package/dist/es/crypto/sm3/index.d.ts +13 -0
  70. package/dist/es/crypto/sm3/index.mjs +24 -0
  71. package/dist/es/crypto/sm3/sm3.d.ts +3 -0
  72. package/dist/es/crypto/sm3/sm3.mjs +197 -0
  73. package/dist/es/crypto/sm4/index.d.ts +56 -0
  74. package/dist/es/crypto/sm4/index.mjs +95 -0
  75. package/dist/es/crypto/sm4/sm4.d.ts +48 -0
  76. package/dist/es/crypto/sm4/sm4.mjs +490 -0
  77. package/dist/es/date/index.d.ts +236 -175
  78. package/dist/es/date/index.mjs +378 -335
  79. package/dist/es/desensitized/index.d.ts +26 -23
  80. package/dist/es/desensitized/index.mjs +21 -18
  81. package/dist/es/device/index.d.ts +31 -25
  82. package/dist/es/device/index.mjs +33 -30
  83. package/dist/es/dom/index.d.ts +32 -29
  84. package/dist/es/dom/index.mjs +26 -23
  85. package/dist/es/file/index.d.ts +30 -30
  86. package/dist/es/file/index.mjs +51 -41
  87. package/dist/es/function/index.d.ts +10 -7
  88. package/dist/es/function/index.mjs +22 -19
  89. package/dist/es/id/index.d.ts +3 -0
  90. package/dist/es/id/index.mjs +6 -2
  91. package/dist/es/index.d.ts +24 -25
  92. package/dist/es/index.mjs +6 -23
  93. package/dist/es/keycode/index.d.ts +6 -6
  94. package/dist/es/keycode/index.mjs +9 -12
  95. package/dist/es/math/index.d.ts +37 -37
  96. package/dist/es/math/index.mjs +113 -81
  97. package/dist/es/number/index.d.ts +7 -7
  98. package/dist/es/number/index.mjs +10 -7
  99. package/dist/es/object/index.d.ts +20 -19
  100. package/dist/es/object/index.mjs +77 -30
  101. package/dist/es/pagination/index.d.ts +39 -6
  102. package/dist/es/pagination/index.mjs +25 -10
  103. package/dist/es/random/index.d.ts +10 -7
  104. package/dist/es/random/index.mjs +8 -5
  105. package/dist/es/regexp/index.d.ts +30 -30
  106. package/dist/es/regexp/index.mjs +23 -20
  107. package/dist/es/storage/index.d.ts +10 -4
  108. package/dist/es/storage/index.mjs +4 -1
  109. package/dist/es/storage/localStorage.d.ts +9 -9
  110. package/dist/es/storage/localStorage.mjs +5 -5
  111. package/dist/es/storage/sessionStorage.d.ts +9 -9
  112. package/dist/es/storage/sessionStorage.mjs +6 -6
  113. package/dist/es/string/index.d.ts +62 -59
  114. package/dist/es/string/index.mjs +66 -63
  115. package/dist/es/url/index.d.ts +65 -65
  116. package/dist/es/url/index.mjs +83 -80
  117. package/dist/es/validate/index.d.ts +83 -80
  118. package/dist/es/validate/index.mjs +122 -106
  119. package/dist/index.d.ts +2355 -2803
  120. package/dist/lib/index.full.umd.js +3297 -9474
  121. package/dist/lib/index.full.umd.min.js +2 -64
  122. package/dist/lib/index.full.umd.min.js.map +1 -1
  123. package/dist/resolver/auto-imports.cjs +38 -31
  124. package/dist/resolver/auto-imports.mjs +38 -31
  125. package/dist/resolver/index.cjs +1 -2
  126. package/dist/resolver/index.d.ts +1 -1
  127. package/dist/resolver/index.mjs +1 -2
  128. package/package.json +96 -90
  129. package/dist/cjs/crypto/aes/aes.cjs +0 -480
  130. package/dist/cjs/crypto/aes/index.cjs +0 -27
  131. package/dist/cjs/crypto/base32/base32.cjs +0 -357
  132. package/dist/cjs/crypto/base32/index.cjs +0 -41
  133. package/dist/cjs/crypto/des/des.cjs +0 -257
  134. package/dist/cjs/crypto/des/index.cjs +0 -28
  135. package/dist/cjs/crypto/sha/sha1/index.cjs +0 -24
  136. package/dist/cjs/crypto/sha/sha1/sha1.cjs +0 -529
  137. package/dist/cjs/crypto/sha/sha256/index.cjs +0 -43
  138. package/dist/cjs/crypto/sha/sha256/sha256.cjs +0 -595
  139. package/dist/cjs/crypto/sha/sha3/index.cjs +0 -41
  140. package/dist/cjs/crypto/sha/sha3/sha3.cjs +0 -624
  141. package/dist/cjs/crypto/sha/sha512/index.cjs +0 -81
  142. package/dist/cjs/crypto/sha/sha512/sha512.cjs +0 -950
  143. package/dist/cjs/crypto/sm/lib/asn1.cjs +0 -149
  144. package/dist/cjs/crypto/sm/lib/ec.cjs +0 -315
  145. package/dist/cjs/crypto/sm/lib/jsbn.cjs +0 -1608
  146. package/dist/cjs/crypto/sm/lib/sm3.cjs +0 -158
  147. package/dist/cjs/crypto/sm/lib/utils.cjs +0 -170
  148. package/dist/cjs/crypto/sm/sm2/index.cjs +0 -112
  149. package/dist/cjs/crypto/sm/sm2/sm2.cjs +0 -231
  150. package/dist/cjs/crypto/sm/sm3/index.cjs +0 -15
  151. package/dist/cjs/crypto/sm/sm3/sm3.cjs +0 -93
  152. package/dist/cjs/crypto/sm/sm4/index.cjs +0 -27
  153. package/dist/cjs/crypto/sm/sm4/sm4.cjs +0 -327
  154. package/dist/cjs/crypto/tea/index.cjs +0 -25
  155. package/dist/cjs/crypto/tea/tea.cjs +0 -187
  156. package/dist/cjs/weapp/index.cjs +0 -142
  157. package/dist/es/crypto/aes/aes.d.ts +0 -156
  158. package/dist/es/crypto/aes/aes.mjs +0 -478
  159. package/dist/es/crypto/aes/index.d.ts +0 -16
  160. package/dist/es/crypto/aes/index.mjs +0 -24
  161. package/dist/es/crypto/base32/base32.d.ts +0 -3
  162. package/dist/es/crypto/base32/base32.mjs +0 -353
  163. package/dist/es/crypto/base32/index.d.ts +0 -24
  164. package/dist/es/crypto/base32/index.mjs +0 -36
  165. package/dist/es/crypto/des/des.d.ts +0 -52
  166. package/dist/es/crypto/des/des.mjs +0 -255
  167. package/dist/es/crypto/des/index.d.ts +0 -14
  168. package/dist/es/crypto/des/index.mjs +0 -25
  169. package/dist/es/crypto/sha/index.d.ts +0 -4
  170. package/dist/es/crypto/sha/sha1/index.d.ts +0 -13
  171. package/dist/es/crypto/sha/sha1/index.mjs +0 -21
  172. package/dist/es/crypto/sha/sha1/sha1.d.ts +0 -2
  173. package/dist/es/crypto/sha/sha1/sha1.mjs +0 -526
  174. package/dist/es/crypto/sha/sha256/index.d.ts +0 -26
  175. package/dist/es/crypto/sha/sha256/index.mjs +0 -38
  176. package/dist/es/crypto/sha/sha256/sha256.d.ts +0 -4
  177. package/dist/es/crypto/sha/sha256/sha256.mjs +0 -590
  178. package/dist/es/crypto/sha/sha3/index.d.ts +0 -24
  179. package/dist/es/crypto/sha/sha3/index.mjs +0 -36
  180. package/dist/es/crypto/sha/sha3/sha3.d.ts +0 -4
  181. package/dist/es/crypto/sha/sha3/sha3.mjs +0 -619
  182. package/dist/es/crypto/sha/sha512/index.d.ts +0 -52
  183. package/dist/es/crypto/sha/sha512/index.mjs +0 -72
  184. package/dist/es/crypto/sha/sha512/sha512.d.ts +0 -8
  185. package/dist/es/crypto/sha/sha512/sha512.mjs +0 -941
  186. package/dist/es/crypto/sm/index.d.ts +0 -3
  187. package/dist/es/crypto/sm/lib/asn1.d.ts +0 -12
  188. package/dist/es/crypto/sm/lib/asn1.mjs +0 -146
  189. package/dist/es/crypto/sm/lib/ec.d.ts +0 -126
  190. package/dist/es/crypto/sm/lib/ec.mjs +0 -312
  191. package/dist/es/crypto/sm/lib/jsbn.d.ts +0 -198
  192. package/dist/es/crypto/sm/lib/jsbn.mjs +0 -1605
  193. package/dist/es/crypto/sm/lib/sm3.d.ts +0 -5
  194. package/dist/es/crypto/sm/lib/sm3.mjs +0 -155
  195. package/dist/es/crypto/sm/lib/utils.d.ts +0 -53
  196. package/dist/es/crypto/sm/lib/utils.mjs +0 -158
  197. package/dist/es/crypto/sm/sm2/index.d.ts +0 -71
  198. package/dist/es/crypto/sm/sm2/index.mjs +0 -101
  199. package/dist/es/crypto/sm/sm2/sm2.d.ts +0 -34
  200. package/dist/es/crypto/sm/sm2/sm2.mjs +0 -220
  201. package/dist/es/crypto/sm/sm3/index.d.ts +0 -7
  202. package/dist/es/crypto/sm/sm3/index.mjs +0 -13
  203. package/dist/es/crypto/sm/sm3/sm3.d.ts +0 -1
  204. package/dist/es/crypto/sm/sm3/sm3.mjs +0 -91
  205. package/dist/es/crypto/sm/sm4/index.d.ts +0 -16
  206. package/dist/es/crypto/sm/sm4/index.mjs +0 -24
  207. package/dist/es/crypto/sm/sm4/sm4.d.ts +0 -2
  208. package/dist/es/crypto/sm/sm4/sm4.mjs +0 -324
  209. package/dist/es/crypto/tea/index.d.ts +0 -14
  210. package/dist/es/crypto/tea/index.mjs +0 -22
  211. package/dist/es/crypto/tea/tea.d.ts +0 -69
  212. package/dist/es/crypto/tea/tea.mjs +0 -185
  213. package/dist/es/weapp/index.d.ts +0 -57
  214. package/dist/es/weapp/index.mjs +0 -131
@@ -0,0 +1,498 @@
1
+ 'use strict';
2
+
3
+ // ========== 常量定义(规范化,避免魔法值) ==========
4
+ const SM4_MODE_ECB = "ecb";
5
+ const SM4_MODE_CBC = "cbc";
6
+ const SM4_PADDING = "pkcs#7";
7
+ const SM4_OUTPUT_HEX = "hex";
8
+ const SM4_OUTPUT_UTF8 = "utf8";
9
+ const SM4_OUTPUT_ARRAY = "array";
10
+ const SM4_OUTPUT_UINT8ARRAY = "uint8array";
11
+ const SM4_OUTPUT_ARRAYBUFFER = "arraybuffer";
12
+ const ENCRYPT = 1;
13
+ const DECRYPT = 0;
14
+ const ROUND_COUNT = 32;
15
+ const BLOCK_SIZE = 16; // 128比特 = 16字节
16
+ const KEY_SIZE = 16; // SM4密钥固定128比特
17
+ const IV_SIZE = 16; // CBC模式IV固定128比特
18
+ // SM4 S盒
19
+ const SBOX = new Uint8Array([
20
+ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, 0x2b, 0x67, 0x9a,
21
+ 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef,
22
+ 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80,
23
+ 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19,
24
+ 0xe6, 0x85, 0x4f, 0xa8, 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d,
25
+ 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 0xd4, 0x00,
26
+ 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 0xea, 0xbf, 0x8a, 0xd2, 0x40,
27
+ 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
28
+ 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23,
29
+ 0xab, 0x0d, 0x53, 0x4e, 0x6f, 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c,
30
+ 0x5b, 0x51, 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 0x0a,
31
+ 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 0x89, 0x69, 0x97, 0x4a,
32
+ 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d,
33
+ 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
34
+ ]);
35
+ // 轮常量 CK
36
+ const CK = new Uint32Array([
37
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5,
38
+ 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1,
39
+ 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed,
40
+ 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
41
+ ]);
42
+ // 系统参数 FK
43
+ const FK = new Uint32Array([0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]);
44
+ // ========== 工具函数(通用转换) ==========
45
+ /**
46
+ * 16进制字符串转Uint8Array
47
+ * @param {string} str - 16进制字符串
48
+ * @returns {Uint8Array} 字节数组
49
+ */
50
+ function hexToUint8Array(str) {
51
+ str = str.replace(/\s+/g, ""); // 去除空格
52
+ if (str.length % 2 !== 0)
53
+ throw new Error("Hex string length must be even");
54
+ const arr = new Uint8Array(str.length / 2);
55
+ for (let i = 0; i < str.length; i += 2) {
56
+ arr[i / 2] = parseInt(str.substr(i, 2), 16) & 0xff;
57
+ }
58
+ return arr;
59
+ }
60
+ /**
61
+ * Uint8Array转16进制字符串
62
+ * @param {Uint8Array} arr - 字节数组
63
+ * @returns {string} 16进制字符串
64
+ */
65
+ function uint8ArrayToHex(arr) {
66
+ return Array.from(arr)
67
+ .map((byte) => {
68
+ const hex = byte.toString(16);
69
+ return hex.length === 1 ? "0" + hex : hex;
70
+ })
71
+ .join("");
72
+ }
73
+ /**
74
+ * UTF8字符串转Uint8Array
75
+ * @param {string} str - UTF8字符串
76
+ * @returns {Uint8Array} 字节数组
77
+ */
78
+ function utf8ToUint8Array(str) {
79
+ return new TextEncoder().encode(str);
80
+ }
81
+ /**
82
+ * Uint8Array转UTF8字符串
83
+ * @param {Uint8Array} arr - 字节数组
84
+ * @returns {string} UTF8字符串
85
+ */
86
+ function uint8ArrayToUtf8(arr) {
87
+ return new TextDecoder("utf-8").decode(arr);
88
+ }
89
+ /**
90
+ * 统一输入数据格式为Uint8Array
91
+ * @param {string|Array|Uint8Array|ArrayBuffer} input - 输入数据
92
+ * @param {number} cryptFlag - ENCRYPT/DECRYPT
93
+ * @returns {Uint8Array} 标准化后的字节数组
94
+ */
95
+ function normalizeInput(input, cryptFlag) {
96
+ if (input instanceof ArrayBuffer) {
97
+ return new Uint8Array(input);
98
+ }
99
+ if (input instanceof Uint8Array) {
100
+ return new Uint8Array(input); // 拷贝避免修改原数组
101
+ }
102
+ if (Array.isArray(input)) {
103
+ return new Uint8Array(input);
104
+ }
105
+ if (typeof input === "string") {
106
+ if (cryptFlag === ENCRYPT) {
107
+ // 加密:字符串按UTF8转字节
108
+ return utf8ToUint8Array(input);
109
+ }
110
+ else {
111
+ // 解密:字符串按16进制转字节
112
+ return hexToUint8Array(input);
113
+ }
114
+ }
115
+ throw new Error(`Unsupported input type: ${typeof input}`);
116
+ }
117
+ /**
118
+ * 标准化密钥/IV为Uint8Array
119
+ * @param {string|Array|Uint8Array|ArrayBuffer} keyOrIv - 密钥/IV
120
+ * @param {number} expectedLength - 期望长度(字节)
121
+ * @param {string} name - 名称(用于报错)
122
+ * @returns {Uint8Array} 标准化后的字节数组
123
+ */
124
+ function normalizeKeyIv(keyOrIv, expectedLength, name) {
125
+ let arr;
126
+ if (typeof keyOrIv === "string") {
127
+ arr = hexToUint8Array(keyOrIv);
128
+ }
129
+ else if (keyOrIv instanceof ArrayBuffer) {
130
+ arr = new Uint8Array(keyOrIv);
131
+ }
132
+ else if (keyOrIv instanceof Uint8Array) {
133
+ arr = keyOrIv;
134
+ }
135
+ else if (Array.isArray(keyOrIv)) {
136
+ arr = new Uint8Array(keyOrIv);
137
+ }
138
+ else {
139
+ throw new Error(`Unsupported ${name} type: ${typeof keyOrIv}`);
140
+ }
141
+ if (arr.length !== expectedLength) {
142
+ throw new Error(`${name} must be ${expectedLength * 8} bits (${expectedLength} bytes)`);
143
+ }
144
+ return arr;
145
+ }
146
+ // ========== SM4核心函数 ==========
147
+ /**
148
+ * 32比特循环左移
149
+ * @param {number} x - 32比特无符号整数
150
+ * @param {number} n - 移位位数
151
+ * @returns {number} 移位结果
152
+ */
153
+ function rotl32(x, n) {
154
+ const s = n & 31;
155
+ return ((x << s) | (x >>> (32 - s))) >>> 0; // >>>0 确保无符号
156
+ }
157
+ /**
158
+ * 非线性变换(字节替换)
159
+ * @param {number} a - 32比特无符号整数
160
+ * @returns {number} 替换结果
161
+ */
162
+ function byteSub(a) {
163
+ return (((SBOX[(a >>> 24) & 0xff] << 24) |
164
+ (SBOX[(a >>> 16) & 0xff] << 16) |
165
+ (SBOX[(a >>> 8) & 0xff] << 8) |
166
+ SBOX[a & 0xff]) >>>
167
+ 0);
168
+ }
169
+ /**
170
+ * 线性变换(加密/解密用)
171
+ * @param {number} b - 32比特无符号整数
172
+ * @returns {number} 变换结果
173
+ */
174
+ function linearTransformEnc(b) {
175
+ return (b ^ rotl32(b, 2) ^ rotl32(b, 10) ^ rotl32(b, 18) ^ rotl32(b, 24)) >>> 0;
176
+ }
177
+ /**
178
+ * 线性变换(密钥扩展用)
179
+ * @param {number} b - 32比特无符号整数
180
+ * @returns {number} 变换结果
181
+ */
182
+ function linearTransformKey(b) {
183
+ return (b ^ rotl32(b, 13) ^ rotl32(b, 23)) >>> 0;
184
+ }
185
+ /**
186
+ * SM4单块加密/解密(128比特)
187
+ * @param {Uint8Array} inputBlock - 输入块(16字节)
188
+ * @param {Uint8Array} outputBlock - 输出块(16字节)
189
+ * @param {Uint32Array} roundKeys - 轮密钥(32个32比特)
190
+ */
191
+ function sm4BlockCrypt(inputBlock, outputBlock, roundKeys) {
192
+ // 确保输入块是16字节
193
+ if (inputBlock.length !== BLOCK_SIZE) {
194
+ throw new Error(`Input block must be ${BLOCK_SIZE} bytes for SM4 block crypt`);
195
+ }
196
+ // 字节数组转32比特字数组(4个字,共128比特)
197
+ const x = new Uint32Array(4);
198
+ for (let i = 0; i < 4; i++) {
199
+ const offset = 4 * i;
200
+ x[i] =
201
+ ((inputBlock[offset] << 24) |
202
+ (inputBlock[offset + 1] << 16) |
203
+ (inputBlock[offset + 2] << 8) |
204
+ inputBlock[offset + 3]) >>>
205
+ 0;
206
+ }
207
+ // 32轮加密
208
+ for (let r = 0; r < ROUND_COUNT; r += 4) {
209
+ let mid = (x[1] ^ x[2] ^ x[3] ^ roundKeys[r]) >>> 0;
210
+ x[0] ^= linearTransformEnc(byteSub(mid));
211
+ mid = (x[2] ^ x[3] ^ x[0] ^ roundKeys[r + 1]) >>> 0;
212
+ x[1] ^= linearTransformEnc(byteSub(mid));
213
+ mid = (x[3] ^ x[0] ^ x[1] ^ roundKeys[r + 2]) >>> 0;
214
+ x[2] ^= linearTransformEnc(byteSub(mid));
215
+ mid = (x[0] ^ x[1] ^ x[2] ^ roundKeys[r + 3]) >>> 0;
216
+ x[3] ^= linearTransformEnc(byteSub(mid));
217
+ }
218
+ // 反序输出
219
+ for (let j = 0; j < BLOCK_SIZE; j += 4) {
220
+ const wordIdx = 3 - j / 4;
221
+ outputBlock[j] = (x[wordIdx] >>> 24) & 0xff;
222
+ outputBlock[j + 1] = (x[wordIdx] >>> 16) & 0xff;
223
+ outputBlock[j + 2] = (x[wordIdx] >>> 8) & 0xff;
224
+ outputBlock[j + 3] = x[wordIdx] & 0xff;
225
+ }
226
+ }
227
+ /**
228
+ * SM4密钥扩展算法
229
+ * @param {Uint8Array} key - 16字节密钥
230
+ * @param {Uint32Array} roundKeys - 输出轮密钥(32个32比特)
231
+ * @param {number} cryptFlag - ENCRYPT/DECRYPT
232
+ */
233
+ function sm4KeyExpansion(key, roundKeys, cryptFlag) {
234
+ // 密钥转32比特字数组
235
+ const x = new Uint32Array(4);
236
+ for (let i = 0; i < 4; i++) {
237
+ const offset = 4 * i;
238
+ x[i] = ((key[offset] << 24) | (key[offset + 1] << 16) | (key[offset + 2] << 8) | key[offset + 3]) >>> 0;
239
+ }
240
+ // 与系统参数异或
241
+ x[0] ^= FK[0];
242
+ x[1] ^= FK[1];
243
+ x[2] ^= FK[2];
244
+ x[3] ^= FK[3];
245
+ // 生成轮密钥
246
+ for (let r = 0; r < ROUND_COUNT; r += 4) {
247
+ let mid = (x[1] ^ x[2] ^ x[3] ^ CK[r]) >>> 0;
248
+ roundKeys[r] = x[0] ^= linearTransformKey(byteSub(mid));
249
+ mid = (x[2] ^ x[3] ^ x[0] ^ CK[r + 1]) >>> 0;
250
+ roundKeys[r + 1] = x[1] ^= linearTransformKey(byteSub(mid));
251
+ mid = (x[3] ^ x[0] ^ x[1] ^ CK[r + 2]) >>> 0;
252
+ roundKeys[r + 2] = x[2] ^= linearTransformKey(byteSub(mid));
253
+ mid = (x[0] ^ x[1] ^ x[2] ^ CK[r + 3]) >>> 0;
254
+ roundKeys[r + 3] = x[3] ^= linearTransformKey(byteSub(mid));
255
+ }
256
+ // 解密时轮密钥反序
257
+ if (cryptFlag === DECRYPT) {
258
+ for (let r = 0; r < 16; r++) {
259
+ const temp = roundKeys[r];
260
+ roundKeys[r] = roundKeys[31 - r];
261
+ roundKeys[31 - r] = temp;
262
+ }
263
+ }
264
+ }
265
+ /**
266
+ * PKCS#7填充
267
+ * @param {Uint8Array} data - 原始数据
268
+ * @returns {Uint8Array} 填充后的数据
269
+ */
270
+ function pkcs7Pad(data) {
271
+ const paddingCount = BLOCK_SIZE - (data.length % BLOCK_SIZE);
272
+ const padded = new Uint8Array(data.length + paddingCount);
273
+ padded.set(data);
274
+ for (let i = 0; i < paddingCount; i++) {
275
+ padded[data.length + i] = paddingCount & 0xff;
276
+ }
277
+ return padded;
278
+ }
279
+ /**
280
+ * PKCS#7去填充
281
+ * @param {Uint8Array} data - 填充后的数据
282
+ * @returns {Uint8Array} 去填充后的数据
283
+ */
284
+ function pkcs7Unpad(data) {
285
+ const paddingCount = data[data.length - 1] & 0xff;
286
+ // 验证填充合法性
287
+ for (let i = 1; i <= paddingCount; i++) {
288
+ if (data[data.length - i] !== paddingCount) {
289
+ throw new Error("Invalid PKCS#7 padding");
290
+ }
291
+ }
292
+ return data.subarray(0, data.length - paddingCount);
293
+ }
294
+ /**
295
+ * SM4主函数
296
+ * @param {string|Array|Uint8Array|ArrayBuffer} inputData - 输入数据
297
+ * @param {string|Array|Uint8Array|ArrayBuffer} key - 16字节密钥
298
+ * @param {number} cryptFlag - ENCRYPT/DECRYPT
299
+ * @param {Object} [options] - 选项
300
+ * @param {string} [options.mode=ecb] - 模式:ecb/cbc
301
+ * @param {string|Array|Uint8Array|ArrayBuffer} [options.iv] - CBC模式IV(16字节)
302
+ * @param {string} [options.padding=pkcs#7] - 填充方式:pkcs#7
303
+ * @param {string} [options.output] - 输出格式:hex/utf8/array/uint8array/arraybuffer
304
+ * @returns {string|Array|Uint8Array|ArrayBuffer} 输出数据
305
+ */
306
+ function sm4Core(inputData, key, cryptFlag, options = {}) {
307
+ // 默认参数(加密和解密默认输出都为hex,避免格式不匹配)
308
+ const { mode = SM4_MODE_ECB, iv = [], padding = SM4_PADDING, output = SM4_OUTPUT_HEX, // 统一默认hex格式
309
+ } = options;
310
+ // 校验模式
311
+ if (![SM4_MODE_ECB, SM4_MODE_CBC].includes(mode)) {
312
+ throw new Error(`Unsupported mode: ${mode}, only 'ecb' and 'cbc' are supported`);
313
+ }
314
+ // 标准化输入、密钥、IV
315
+ const input = normalizeInput(inputData, cryptFlag);
316
+ const keyBytes = normalizeKeyIv(key, KEY_SIZE, "key");
317
+ let ivBytes = new Uint8Array(IV_SIZE);
318
+ if (mode === SM4_MODE_CBC) {
319
+ ivBytes = normalizeKeyIv(iv, IV_SIZE, "IV");
320
+ }
321
+ // 填充(仅加密时)
322
+ let processedInput = input;
323
+ if (padding === SM4_PADDING && cryptFlag === ENCRYPT) {
324
+ processedInput = pkcs7Pad(input);
325
+ // 确保填充后是16字节的倍数
326
+ if (processedInput.length % BLOCK_SIZE !== 0) {
327
+ throw new Error("PKCS7 padding failed: data length is not multiple of block size");
328
+ }
329
+ }
330
+ // 生成轮密钥
331
+ const roundKeys = new Uint32Array(ROUND_COUNT);
332
+ sm4KeyExpansion(keyBytes, roundKeys, cryptFlag);
333
+ // 初始化输出缓冲区
334
+ const outputData = new Uint8Array(processedInput.length);
335
+ let lastVector = new Uint8Array(ivBytes); // CBC模式向量
336
+ let point = 0;
337
+ // 分块处理(严格按16字节分块)
338
+ while (point < processedInput.length) {
339
+ const inputBlock = processedInput.subarray(point, point + BLOCK_SIZE);
340
+ const outputBlock = new Uint8Array(BLOCK_SIZE);
341
+ if (mode === SM4_MODE_CBC) {
342
+ if (cryptFlag === ENCRYPT) {
343
+ // CBC加密:输入块与前向量异或
344
+ const xorBlock = new Uint8Array(BLOCK_SIZE);
345
+ for (let i = 0; i < BLOCK_SIZE; i++) {
346
+ xorBlock[i] = (inputBlock[i] ^ lastVector[i]) & 0xff;
347
+ }
348
+ sm4BlockCrypt(xorBlock, outputBlock, roundKeys);
349
+ }
350
+ else {
351
+ // CBC解密:先加密再异或
352
+ sm4BlockCrypt(inputBlock, outputBlock, roundKeys);
353
+ for (let i = 0; i < BLOCK_SIZE; i++) {
354
+ outputBlock[i] = (outputBlock[i] ^ lastVector[i]) & 0xff;
355
+ }
356
+ }
357
+ // 更新向量
358
+ lastVector = cryptFlag === ENCRYPT ? outputBlock : inputBlock;
359
+ }
360
+ else {
361
+ // ECB模式(严格调用块加密)
362
+ sm4BlockCrypt(inputBlock, outputBlock, roundKeys);
363
+ }
364
+ // 写入输出
365
+ outputData.set(outputBlock, point);
366
+ point += BLOCK_SIZE;
367
+ }
368
+ // 去填充(仅解密时)
369
+ let finalOutput = outputData;
370
+ if (padding === SM4_PADDING && cryptFlag === DECRYPT) {
371
+ finalOutput = pkcs7Unpad(outputData);
372
+ }
373
+ // 转换输出格式(解密时如果输出是utf8,先转hex再转utf8)
374
+ if (cryptFlag === DECRYPT && output === SM4_OUTPUT_UTF8) {
375
+ return uint8ArrayToUtf8(finalOutput);
376
+ }
377
+ switch (output) {
378
+ case SM4_OUTPUT_HEX:
379
+ return uint8ArrayToHex(finalOutput);
380
+ case SM4_OUTPUT_ARRAY:
381
+ return Array.from(finalOutput);
382
+ case SM4_OUTPUT_UINT8ARRAY:
383
+ return finalOutput;
384
+ case SM4_OUTPUT_ARRAYBUFFER:
385
+ return finalOutput.buffer;
386
+ default:
387
+ throw new Error(`Unsupported output format: ${output}`);
388
+ }
389
+ }
390
+ // ========== 便捷API(函数式,符合设计准则) ==========
391
+ /**
392
+ * 生成 SM4 CBC 模式专用的安全随机 IV(16字节)
393
+ * @param {string} [outputFormat=SM4_OUTPUT_HEX] - 输出格式:hex/uint8array/array/arraybuffer
394
+ * @returns {string|Uint8Array|Array|ArrayBuffer} 随机IV
395
+ */
396
+ function generateIv(outputFormat = SM4_OUTPUT_HEX) {
397
+ // 1. 校验浏览器是否支持 crypto
398
+ if (!window?.crypto?.getRandomValues) {
399
+ throw new Error("Your browser does not support secure random generation (crypto API)");
400
+ }
401
+ // 2. 生成 16 字节安全随机数
402
+ const ivUint8 = new Uint8Array(IV_SIZE);
403
+ window.crypto.getRandomValues(ivUint8);
404
+ // 3. 用导出的常量做格式判断,新增 ArrayBuffer 支持
405
+ switch (outputFormat) {
406
+ case SM4_OUTPUT_UINT8ARRAY:
407
+ return ivUint8;
408
+ case SM4_OUTPUT_ARRAY:
409
+ return Array.from(ivUint8).map((byte) => Number(byte));
410
+ case SM4_OUTPUT_ARRAYBUFFER: // 新增:支持 ArrayBuffer 格式
411
+ return ivUint8.buffer;
412
+ case SM4_OUTPUT_HEX:
413
+ default:
414
+ return Array.from(ivUint8)
415
+ .map((byte) => {
416
+ const hex = byte.toString(16);
417
+ return hex.length === 1 ? `0${hex}` : hex;
418
+ })
419
+ .join("");
420
+ }
421
+ }
422
+ /**
423
+ * 生成 SM4 标准密钥(16字节/32位16进制字符串)
424
+ * @param {string} [outputFormat=SM4_OUTPUT_HEX] - 输出格式:hex/uint8array/array/arraybuffer
425
+ * @returns {string|Uint8Array|number[]|ArrayBuffer} 16字节SM4密钥
426
+ */
427
+ function generateKey(outputFormat = SM4_OUTPUT_HEX) {
428
+ // 校验浏览器/Node环境的安全随机数API
429
+ if (!window?.crypto?.getRandomValues && !global?.crypto?.getRandomValues) {
430
+ throw new Error("当前环境不支持安全随机数生成,请升级浏览器/Node.js");
431
+ }
432
+ // 生成16字节随机数(SM4密钥固定16字节)
433
+ const cryptoObj = window?.crypto || global?.crypto;
434
+ const keyUint8 = new Uint8Array(16);
435
+ cryptoObj.getRandomValues(keyUint8);
436
+ // 按格式返回(用常量替代硬编码字符串,新增 ArrayBuffer 支持)
437
+ switch (outputFormat) {
438
+ case SM4_OUTPUT_UINT8ARRAY:
439
+ return keyUint8;
440
+ case SM4_OUTPUT_ARRAY:
441
+ return Array.from(keyUint8).map((byte) => Number(byte));
442
+ case SM4_OUTPUT_ARRAYBUFFER: // 新增:支持 ArrayBuffer 格式
443
+ return keyUint8.buffer;
444
+ case SM4_OUTPUT_HEX:
445
+ default:
446
+ return Array.from(keyUint8)
447
+ .map((byte) => byte.toString(16).padStart(2, "0"))
448
+ .join("");
449
+ }
450
+ }
451
+ /**
452
+ * SM4加密
453
+ * @param {string|Array|Uint8Array|ArrayBuffer} input - 输入数据(字符串/字节)
454
+ * @param {string|Array|Uint8Array|ArrayBuffer} key - 16字节密钥
455
+ * @param {Object} [options] - 选项
456
+ * @returns {string|Array|Uint8Array|ArrayBuffer} 加密结果
457
+ */
458
+ function encrypt(input, key, options = {}) {
459
+ return sm4Core(input, key, ENCRYPT, options);
460
+ }
461
+ /**
462
+ * SM4解密
463
+ * @param {string|Array|Uint8Array|ArrayBuffer} input - 加密数据(16进制字符串/字节)
464
+ * @param {string|Array|Uint8Array|ArrayBuffer} key - 16字节密钥
465
+ * @param {Object} [options] - 选项
466
+ * @returns {string|Array|Uint8Array|ArrayBuffer} 解密结果
467
+ */
468
+ function decrypt(input, key, options = {}) {
469
+ // 解密时如果没传output,默认按加密的output格式(hex)处理,再转utf8
470
+ const finalOptions = {
471
+ output: SM4_OUTPUT_UTF8, // 解密默认返回utf8字符串
472
+ ...options,
473
+ };
474
+ return sm4Core(input, key, DECRYPT, finalOptions);
475
+ }
476
+ // 导出模式
477
+ const MODE = {
478
+ ECB: SM4_MODE_ECB,
479
+ CBC: SM4_MODE_CBC,
480
+ };
481
+ // 导出填充
482
+ const PADDING = SM4_PADDING;
483
+ // 导出输出模式
484
+ const OUTPUT = {
485
+ HEX: SM4_OUTPUT_HEX,
486
+ UTF8: SM4_OUTPUT_UTF8,
487
+ ARRAY: SM4_OUTPUT_ARRAY,
488
+ UINT8ARRAY: SM4_OUTPUT_UINT8ARRAY,
489
+ ARRAYBUFFER: SM4_OUTPUT_ARRAYBUFFER,
490
+ };
491
+
492
+ exports.MODE = MODE;
493
+ exports.OUTPUT = OUTPUT;
494
+ exports.PADDING = PADDING;
495
+ exports.decrypt = decrypt;
496
+ exports.encrypt = encrypt;
497
+ exports.generateIv = generateIv;
498
+ exports.generateKey = generateKey;