simple-crypto-utils 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 (225) hide show
  1. package/dist/crypto/decrypt.d.ts +1 -0
  2. package/dist/crypto/decrypt.d.ts.map +1 -0
  3. package/dist/crypto/decrypt.js +2 -0
  4. package/dist/crypto/decrypt.js.map +1 -0
  5. package/dist/crypto/encrypt.d.ts +1 -0
  6. package/dist/crypto/encrypt.d.ts.map +1 -0
  7. package/dist/crypto/encrypt.js +2 -0
  8. package/dist/crypto/encrypt.js.map +1 -0
  9. package/dist/crypto/signMessage.d.ts +1 -0
  10. package/dist/crypto/signMessage.d.ts.map +1 -0
  11. package/dist/crypto/signMessage.js +2 -0
  12. package/dist/crypto/signMessage.js.map +1 -0
  13. package/dist/crypto/verifyMessage.d.ts +1 -0
  14. package/dist/crypto/verifyMessage.d.ts.map +1 -0
  15. package/dist/crypto/verifyMessage.js +2 -0
  16. package/dist/crypto/verifyMessage.js.map +1 -0
  17. package/dist/crypto-asymmetricaly/file/decryptFile.d.ts +2 -0
  18. package/dist/crypto-asymmetricaly/file/decryptFile.d.ts.map +1 -0
  19. package/dist/crypto-asymmetricaly/file/decryptFile.js +93 -0
  20. package/dist/crypto-asymmetricaly/file/decryptFile.js.map +1 -0
  21. package/dist/crypto-asymmetricaly/file/encryptFile.d.ts +3 -0
  22. package/dist/crypto-asymmetricaly/file/encryptFile.d.ts.map +1 -0
  23. package/dist/crypto-asymmetricaly/file/encryptFile.js +110 -0
  24. package/dist/crypto-asymmetricaly/file/encryptFile.js.map +1 -0
  25. package/dist/crypto-asymmetricaly/index.d.ts +5 -0
  26. package/dist/crypto-asymmetricaly/index.d.ts.map +1 -0
  27. package/dist/crypto-asymmetricaly/index.js +5 -0
  28. package/dist/crypto-asymmetricaly/index.js.map +1 -0
  29. package/dist/crypto-asymmetricaly/keys/generateRSA.d.ts +5 -0
  30. package/dist/crypto-asymmetricaly/keys/generateRSA.d.ts.map +1 -0
  31. package/dist/crypto-asymmetricaly/keys/generateRSA.js +24 -0
  32. package/dist/crypto-asymmetricaly/keys/generateRSA.js.map +1 -0
  33. package/dist/crypto-asymmetricaly/rsa/unwrapKey.d.ts +1 -0
  34. package/dist/crypto-asymmetricaly/rsa/unwrapKey.d.ts.map +1 -0
  35. package/dist/crypto-asymmetricaly/rsa/unwrapKey.js +2 -0
  36. package/dist/crypto-asymmetricaly/rsa/unwrapKey.js.map +1 -0
  37. package/dist/crypto-asymmetricaly/rsa/wrapKey.d.ts +1 -0
  38. package/dist/crypto-asymmetricaly/rsa/wrapKey.d.ts.map +1 -0
  39. package/dist/crypto-asymmetricaly/rsa/wrapKey.js +2 -0
  40. package/dist/crypto-asymmetricaly/rsa/wrapKey.js.map +1 -0
  41. package/dist/crypto-asymmetricaly/string/decryptString.d.ts +2 -0
  42. package/dist/crypto-asymmetricaly/string/decryptString.d.ts.map +1 -0
  43. package/dist/crypto-asymmetricaly/string/decryptString.js +47 -0
  44. package/dist/crypto-asymmetricaly/string/decryptString.js.map +1 -0
  45. package/dist/crypto-asymmetricaly/string/encryptString.d.ts +7 -0
  46. package/dist/crypto-asymmetricaly/string/encryptString.d.ts.map +1 -0
  47. package/dist/crypto-asymmetricaly/string/encryptString.js +26 -0
  48. package/dist/crypto-asymmetricaly/string/encryptString.js.map +1 -0
  49. package/dist/crypto-asymmetricaly/string/generateAES.d.ts +5 -0
  50. package/dist/crypto-asymmetricaly/string/generateAES.d.ts.map +1 -0
  51. package/dist/crypto-asymmetricaly/string/generateAES.js +7 -0
  52. package/dist/crypto-asymmetricaly/string/generateAES.js.map +1 -0
  53. package/dist/crypto-symmetricaly/decrypt.d.ts +2 -0
  54. package/dist/crypto-symmetricaly/decrypt.d.ts.map +1 -0
  55. package/dist/crypto-symmetricaly/decrypt.js +14 -0
  56. package/dist/crypto-symmetricaly/decrypt.js.map +1 -0
  57. package/dist/crypto-symmetricaly/encrypt.d.ts +2 -0
  58. package/dist/crypto-symmetricaly/encrypt.d.ts.map +1 -0
  59. package/dist/crypto-symmetricaly/encrypt.js +16 -0
  60. package/dist/crypto-symmetricaly/encrypt.js.map +1 -0
  61. package/dist/crypto-symmetricaly/index.d.ts +3 -0
  62. package/dist/crypto-symmetricaly/index.d.ts.map +1 -0
  63. package/dist/crypto-symmetricaly/index.js +3 -0
  64. package/dist/crypto-symmetricaly/index.js.map +1 -0
  65. package/dist/crypto-symmetricaly/signMessage.d.ts +1 -0
  66. package/dist/crypto-symmetricaly/signMessage.d.ts.map +1 -0
  67. package/dist/crypto-symmetricaly/signMessage.js +2 -0
  68. package/dist/crypto-symmetricaly/signMessage.js.map +1 -0
  69. package/dist/crypto-symmetricaly/verifyMessage.d.ts +1 -0
  70. package/dist/crypto-symmetricaly/verifyMessage.d.ts.map +1 -0
  71. package/dist/crypto-symmetricaly/verifyMessage.js +2 -0
  72. package/dist/crypto-symmetricaly/verifyMessage.js.map +1 -0
  73. package/dist/hash/hash.d.ts +2 -0
  74. package/dist/hash/hash.d.ts.map +1 -0
  75. package/dist/hash/hash.js +7 -0
  76. package/dist/hash/hash.js.map +1 -0
  77. package/dist/hash/hashHmac.d.ts +2 -0
  78. package/dist/hash/hashHmac.d.ts.map +1 -0
  79. package/dist/hash/hashHmac.js +5 -0
  80. package/dist/hash/hashHmac.js.map +1 -0
  81. package/dist/hash/index.d.ts +4 -0
  82. package/dist/hash/index.d.ts.map +1 -0
  83. package/dist/hash/index.js +4 -0
  84. package/dist/hash/index.js.map +1 -0
  85. package/dist/hash/verifyHmac.d.ts +2 -0
  86. package/dist/hash/verifyHmac.d.ts.map +1 -0
  87. package/dist/hash/verifyHmac.js +10 -0
  88. package/dist/hash/verifyHmac.js.map +1 -0
  89. package/dist/index.cjs +1569 -0
  90. package/dist/index.d.cts +350 -0
  91. package/dist/index.d.ts +350 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +1546 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/otp/TOTP.d.ts +10 -0
  96. package/dist/otp/TOTP.d.ts.map +1 -0
  97. package/dist/otp/TOTP.js +33 -0
  98. package/dist/otp/TOTP.js.map +1 -0
  99. package/dist/otp/generate.d.ts +2 -0
  100. package/dist/otp/generate.d.ts.map +1 -0
  101. package/dist/otp/generate.js +7 -0
  102. package/dist/otp/generate.js.map +1 -0
  103. package/dist/otp/generateOTP.d.ts +1 -0
  104. package/dist/otp/generateOTP.d.ts.map +1 -0
  105. package/dist/otp/generateOTP.js +2 -0
  106. package/dist/otp/generateOTP.js.map +1 -0
  107. package/dist/otp/hash.d.ts +2 -0
  108. package/dist/otp/hash.d.ts.map +1 -0
  109. package/dist/otp/hash.js +5 -0
  110. package/dist/otp/hash.js.map +1 -0
  111. package/dist/otp/index.d.ts +3 -0
  112. package/dist/otp/index.d.ts.map +1 -0
  113. package/dist/otp/index.js +3 -0
  114. package/dist/otp/index.js.map +1 -0
  115. package/dist/otp/verifyOTP.d.ts +1 -0
  116. package/dist/otp/verifyOTP.d.ts.map +1 -0
  117. package/dist/otp/verifyOTP.js +2 -0
  118. package/dist/otp/verifyOTP.js.map +1 -0
  119. package/dist/password/generate.d.ts +15 -0
  120. package/dist/password/generate.d.ts.map +1 -0
  121. package/dist/password/generate.js +44 -0
  122. package/dist/password/generate.js.map +1 -0
  123. package/dist/password/generatePassword.d.ts +2 -0
  124. package/dist/password/generatePassword.d.ts.map +1 -0
  125. package/dist/password/generatePassword.js +10 -0
  126. package/dist/password/generatePassword.js.map +1 -0
  127. package/dist/password/hash.d.ts +2 -0
  128. package/dist/password/hash.d.ts.map +1 -0
  129. package/dist/password/hash.js +12 -0
  130. package/dist/password/hash.js.map +1 -0
  131. package/dist/password/hashPassword.d.ts +1 -0
  132. package/dist/password/hashPassword.d.ts.map +1 -0
  133. package/dist/password/hashPassword.js +2 -0
  134. package/dist/password/hashPassword.js.map +1 -0
  135. package/dist/password/index.d.ts +4 -0
  136. package/dist/password/index.d.ts.map +1 -0
  137. package/dist/password/index.js +4 -0
  138. package/dist/password/index.js.map +1 -0
  139. package/dist/password/validatePassword.d.ts +1 -0
  140. package/dist/password/validatePassword.d.ts.map +1 -0
  141. package/dist/password/validatePassword.js +2 -0
  142. package/dist/password/validatePassword.js.map +1 -0
  143. package/dist/password/verify.d.ts +2 -0
  144. package/dist/password/verify.d.ts.map +1 -0
  145. package/dist/password/verify.js +33 -0
  146. package/dist/password/verify.js.map +1 -0
  147. package/dist/password/verifyPassword.d.ts +1 -0
  148. package/dist/password/verifyPassword.d.ts.map +1 -0
  149. package/dist/password/verifyPassword.js +2 -0
  150. package/dist/password/verifyPassword.js.map +1 -0
  151. package/dist/signature/index.d.ts +46 -0
  152. package/dist/signature/index.d.ts.map +1 -0
  153. package/dist/signature/index.js +51 -0
  154. package/dist/signature/index.js.map +1 -0
  155. package/dist/signature/serialize.d.ts +4 -0
  156. package/dist/signature/serialize.d.ts.map +1 -0
  157. package/dist/signature/serialize.js +33 -0
  158. package/dist/signature/serialize.js.map +1 -0
  159. package/dist/signature/sign.d.ts +3 -0
  160. package/dist/signature/sign.d.ts.map +1 -0
  161. package/dist/signature/sign.js +26 -0
  162. package/dist/signature/sign.js.map +1 -0
  163. package/dist/signature/types.d.ts +16 -0
  164. package/dist/signature/types.d.ts.map +1 -0
  165. package/dist/signature/types.js +2 -0
  166. package/dist/signature/types.js.map +1 -0
  167. package/dist/signature/verify.d.ts +3 -0
  168. package/dist/signature/verify.d.ts.map +1 -0
  169. package/dist/signature/verify.js +26 -0
  170. package/dist/signature/verify.js.map +1 -0
  171. package/dist/test-minimal.d.ts +1 -0
  172. package/dist/test-minimal.d.ts.map +1 -0
  173. package/dist/test-minimal.js +4 -0
  174. package/dist/test-minimal.js.map +1 -0
  175. package/dist/test.d.ts +2 -0
  176. package/dist/test.d.ts.map +1 -0
  177. package/dist/test.js +33 -0
  178. package/dist/test.js.map +1 -0
  179. package/dist/token/generateRandomToken.d.ts +1 -0
  180. package/dist/token/generateRandomToken.d.ts.map +1 -0
  181. package/dist/token/generateRandomToken.js +2 -0
  182. package/dist/token/generateRandomToken.js.map +1 -0
  183. package/dist/token/generateUUID.d.ts +1 -0
  184. package/dist/token/generateUUID.d.ts.map +1 -0
  185. package/dist/token/generateUUID.js +2 -0
  186. package/dist/token/generateUUID.js.map +1 -0
  187. package/dist/token/hashToken.d.ts +1 -0
  188. package/dist/token/hashToken.d.ts.map +1 -0
  189. package/dist/token/hashToken.js +2 -0
  190. package/dist/token/hashToken.js.map +1 -0
  191. package/dist/utlis/constants.d.ts +4 -0
  192. package/dist/utlis/constants.d.ts.map +1 -0
  193. package/dist/utlis/constants.js +4 -0
  194. package/dist/utlis/constants.js.map +1 -0
  195. package/dist/utlis/entropyScore.d.ts +1 -0
  196. package/dist/utlis/entropyScore.d.ts.map +1 -0
  197. package/dist/utlis/entropyScore.js +2 -0
  198. package/dist/utlis/entropyScore.js.map +1 -0
  199. package/dist/utlis/generateRandomBytes.d.ts +2 -0
  200. package/dist/utlis/generateRandomBytes.d.ts.map +1 -0
  201. package/dist/utlis/generateRandomBytes.js +9 -0
  202. package/dist/utlis/generateRandomBytes.js.map +1 -0
  203. package/dist/utlis/maskSensitive.d.ts +1 -0
  204. package/dist/utlis/maskSensitive.d.ts.map +1 -0
  205. package/dist/utlis/maskSensitive.js +2 -0
  206. package/dist/utlis/maskSensitive.js.map +1 -0
  207. package/dist/utlis/safeCompare.d.ts +1 -0
  208. package/dist/utlis/safeCompare.d.ts.map +1 -0
  209. package/dist/utlis/safeCompare.js +2 -0
  210. package/dist/utlis/safeCompare.js.map +1 -0
  211. package/dist/uuid/generate.d.ts +2 -0
  212. package/dist/uuid/generate.d.ts.map +1 -0
  213. package/dist/uuid/generate.js +5 -0
  214. package/dist/uuid/generate.js.map +1 -0
  215. package/dist/uuid/hashToken.d.ts +1 -0
  216. package/dist/uuid/hashToken.d.ts.map +1 -0
  217. package/dist/uuid/hashToken.js +6 -0
  218. package/dist/uuid/hashToken.js.map +1 -0
  219. package/dist/uuid/index.d.ts +2 -0
  220. package/dist/uuid/index.d.ts.map +1 -0
  221. package/dist/uuid/index.js +2 -0
  222. package/dist/uuid/index.js.map +1 -0
  223. package/license +18 -0
  224. package/package.json +74 -0
  225. package/readme.md +697 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1569 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ LIBRARY_VERSION: () => LIBRARY_VERSION,
24
+ MAX_MESSAGE_AGE: () => MAX_MESSAGE_AGE,
25
+ MESSAGE_MAX_AGE_MS: () => MESSAGE_MAX_AGE_MS,
26
+ MINIMUM_PASSWORD_LENGTH: () => MINIMUM_PASSWORD_LENGTH,
27
+ MIN_PASSWORD_LENGTH: () => MIN_PASSWORD_LENGTH,
28
+ VERSION: () => VERSION,
29
+ decrypt: () => decrypt,
30
+ decryptFile: () => decryptFile,
31
+ decryptMessage: () => decryptMessage,
32
+ deriveAESKeyForDecryption: () => deriveAESKeyForDecryption,
33
+ deriveAESKeyForEncryption: () => deriveAESKeyForEncryption,
34
+ encrypt: () => encrypt,
35
+ encryptFileStreaming: () => encryptFileStreaming,
36
+ encryptMessage: () => encryptMessage,
37
+ hash: () => hash_exports,
38
+ keys: () => keys_exports,
39
+ otp: () => otp_exports,
40
+ password: () => password_exports,
41
+ signature: () => signature_exports,
42
+ uuid: () => uuid_exports,
43
+ validatePassword: () => validatePassword,
44
+ validatePrivateKey: () => validatePrivateKey,
45
+ validatePublicKey: () => validatePublicKey,
46
+ validateTimestamp: () => validateTimestamp,
47
+ validateVersion: () => validateVersion
48
+ });
49
+ module.exports = __toCommonJS(index_exports);
50
+
51
+ // src/crypto/encrypt.ts
52
+ var import_fs = require("fs");
53
+ var import_promises = require("fs/promises");
54
+ var import_crypto = require("crypto");
55
+ var import_promises2 = require("stream/promises");
56
+ var import_os = require("os");
57
+ var import_path = require("path");
58
+ var VERSION = 1;
59
+ var MIN_PASSWORD_LENGTH = 12;
60
+ var MESSAGE_MAX_AGE_MS = 5 * 60 * 1e3;
61
+ function validatePassword(password, strictMode = false) {
62
+ if (!password || password.length < MIN_PASSWORD_LENGTH) {
63
+ throw new Error(
64
+ `Password must be at least ${MIN_PASSWORD_LENGTH} characters`
65
+ );
66
+ }
67
+ const hasUpperCase = /[A-Z]/.test(password);
68
+ const hasLowerCase = /[a-z]/.test(password);
69
+ const hasNumber = /[0-9]/.test(password);
70
+ const hasSpecial = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password);
71
+ const strength = [hasUpperCase, hasLowerCase, hasNumber, hasSpecial].filter(
72
+ Boolean
73
+ ).length;
74
+ if (strictMode && strength < 3) {
75
+ throw new Error(
76
+ "Strict mode: password must contain uppercase, lowercase, numbers, and special characters"
77
+ );
78
+ }
79
+ if (!strictMode && strength < 2) {
80
+ console.warn(
81
+ "\u26A0\uFE0F Weak password: consider using uppercase, lowercase, numbers, and special characters"
82
+ );
83
+ }
84
+ }
85
+ function validatePublicKey(keyStr, expectedType) {
86
+ try {
87
+ const keyBuffer = Buffer.from(keyStr, "base64");
88
+ const key = (0, import_crypto.createPublicKey)({
89
+ key: keyBuffer,
90
+ format: "der",
91
+ type: "spki"
92
+ });
93
+ if (key.asymmetricKeyType !== expectedType) {
94
+ throw new Error(
95
+ `Expected ${expectedType} key, got ${key.asymmetricKeyType}`
96
+ );
97
+ }
98
+ } catch (err) {
99
+ throw new Error(`Invalid ${expectedType} public key: ${err.message}`);
100
+ }
101
+ }
102
+ function validatePrivateKey(keyStr, expectedType) {
103
+ try {
104
+ const keyBuffer = Buffer.from(keyStr, "base64");
105
+ const key = (0, import_crypto.createPrivateKey)({
106
+ key: keyBuffer,
107
+ format: "der",
108
+ type: "pkcs8"
109
+ });
110
+ if (key.asymmetricKeyType !== expectedType) {
111
+ throw new Error(
112
+ `Expected ${expectedType} key, got ${key.asymmetricKeyType}`
113
+ );
114
+ }
115
+ } catch (err) {
116
+ throw new Error(`Invalid ${expectedType} private key: ${err.message}`);
117
+ }
118
+ }
119
+ async function secureDelete(filePath) {
120
+ try {
121
+ await (0, import_promises.unlink)(filePath);
122
+ } catch (err) {
123
+ console.error(`\u26A0\uFE0F Failed to delete temp file ${filePath}:`, err.message);
124
+ }
125
+ }
126
+ function createTimestampBuffer() {
127
+ const timestamp = Date.now();
128
+ const buf = Buffer.alloc(8);
129
+ buf.writeBigUInt64BE(BigInt(timestamp), 0);
130
+ return buf;
131
+ }
132
+ async function encrypt(options, data, inputPath, outputPath) {
133
+ if (!data && !inputPath) {
134
+ throw new Error("No data to encrypt");
135
+ }
136
+ if (options.strictMode) {
137
+ console.log("\u{1F512} Strict mode enabled - all security checks active");
138
+ }
139
+ const isFile = inputPath && outputPath;
140
+ if (isFile) {
141
+ await encryptFile(options, inputPath, outputPath);
142
+ return { type: "file", outputPath };
143
+ } else {
144
+ let messageData;
145
+ if (Buffer.isBuffer(data)) {
146
+ messageData = data.toString("utf8");
147
+ } else if (typeof data === "string") {
148
+ messageData = data;
149
+ } else {
150
+ messageData = data;
151
+ }
152
+ const encrypted = encryptMessage(options, messageData);
153
+ return { type: "message", data: encrypted };
154
+ }
155
+ }
156
+ async function encryptFile(options, inputPath, outputPath) {
157
+ await encryptFileStreaming(options, inputPath, outputPath);
158
+ }
159
+ async function encryptFileStreaming(options, inputPath, outputPath) {
160
+ const aesKey = (0, import_crypto.randomBytes)(32);
161
+ const iv = (0, import_crypto.randomBytes)(12);
162
+ const tempPath = (0, import_path.join)(
163
+ (0, import_os.tmpdir)(),
164
+ `temp-encrypt-${Date.now()}-${(0, import_crypto.randomBytes)(4).toString("hex")}.tmp`
165
+ );
166
+ try {
167
+ const tempStream = (0, import_fs.createWriteStream)(tempPath);
168
+ const inputStream = (0, import_fs.createReadStream)(inputPath);
169
+ let header;
170
+ switch (options.type) {
171
+ case "symmetric-password":
172
+ validatePassword(options.password, options.strictMode);
173
+ const salt = (0, import_crypto.randomBytes)(16);
174
+ const key = (0, import_crypto.scryptSync)(options.password, salt, 32);
175
+ const cipherSymmetric = (0, import_crypto.createCipheriv)("aes-256-gcm", key, iv);
176
+ await (0, import_promises2.pipeline)(inputStream, cipherSymmetric, tempStream);
177
+ const authTagSymmetric = cipherSymmetric.getAuthTag();
178
+ header = {
179
+ version: VERSION,
180
+ iv: iv.toString("base64"),
181
+ authTag: authTagSymmetric.toString("base64"),
182
+ salt: salt.toString("base64")
183
+ };
184
+ break;
185
+ case "sealEnvelope":
186
+ validatePublicKey(options.recipientPublicKey, "rsa");
187
+ const cipherSeal = (0, import_crypto.createCipheriv)("aes-256-gcm", aesKey, iv);
188
+ await (0, import_promises2.pipeline)(inputStream, cipherSeal, tempStream);
189
+ const authTagSeal = cipherSeal.getAuthTag();
190
+ const recipientPubKey = (0, import_crypto.createPublicKey)({
191
+ key: Buffer.from(options.recipientPublicKey, "base64"),
192
+ format: "der",
193
+ type: "spki"
194
+ });
195
+ const encryptedAESKey = (0, import_crypto.publicEncrypt)(
196
+ {
197
+ key: recipientPubKey,
198
+ // Use KeyObject instead of string
199
+ padding: import_crypto.constants.RSA_PKCS1_OAEP_PADDING,
200
+ oaepHash: "sha256"
201
+ },
202
+ aesKey
203
+ );
204
+ header = {
205
+ version: VERSION,
206
+ encryptedKey: encryptedAESKey.toString("base64"),
207
+ iv: iv.toString("base64"),
208
+ authTag: authTagSeal.toString("base64")
209
+ };
210
+ break;
211
+ case "secure-channel":
212
+ validatePublicKey(options.recipientPublicKey, "x25519");
213
+ const ephemeralData = deriveAESKeyForEncryption(
214
+ options.recipientPublicKey
215
+ );
216
+ const cipherECDH = (0, import_crypto.createCipheriv)(
217
+ "aes-256-gcm",
218
+ ephemeralData.aesKey,
219
+ iv
220
+ );
221
+ await (0, import_promises2.pipeline)(inputStream, cipherECDH, tempStream);
222
+ const authTagECDH = cipherECDH.getAuthTag();
223
+ header = {
224
+ version: VERSION,
225
+ ephemeralPublicKey: ephemeralData.ephemeralPublicKey,
226
+ salt: ephemeralData.salt.toString("base64"),
227
+ iv: iv.toString("base64"),
228
+ authTag: authTagECDH.toString("base64")
229
+ };
230
+ if (options.includeTimestamp !== false) {
231
+ header.timestamp = Date.now();
232
+ }
233
+ break;
234
+ case "authenticated-channel":
235
+ validatePublicKey(options.recipientPublicKey, "x25519");
236
+ validatePrivateKey(options.senderPrivateKey, "ed25519");
237
+ const ephemeralAuthData = deriveAESKeyForEncryption(
238
+ options.recipientPublicKey
239
+ );
240
+ const cipherAuth = (0, import_crypto.createCipheriv)(
241
+ "aes-256-gcm",
242
+ ephemeralAuthData.aesKey,
243
+ iv
244
+ );
245
+ await (0, import_promises2.pipeline)(inputStream, cipherAuth, tempStream);
246
+ const authTagAuth = cipherAuth.getAuthTag();
247
+ const senderPrivKey = (0, import_crypto.createPrivateKey)({
248
+ key: Buffer.from(options.senderPrivateKey, "base64"),
249
+ format: "der",
250
+ type: "pkcs8"
251
+ });
252
+ const dataToSign = Buffer.concat([
253
+ Buffer.from(ephemeralAuthData.ephemeralPublicKey, "base64"),
254
+ iv,
255
+ authTagAuth
256
+ ]);
257
+ const signature = (0, import_crypto.sign)(null, dataToSign, senderPrivKey);
258
+ header = {
259
+ version: VERSION,
260
+ ephemeralPublicKey: ephemeralAuthData.ephemeralPublicKey,
261
+ salt: ephemeralAuthData.salt.toString("base64"),
262
+ signature: signature.toString("base64"),
263
+ iv: iv.toString("base64"),
264
+ authTag: authTagAuth.toString("base64")
265
+ };
266
+ if (options.includeTimestamp !== false) {
267
+ header.timestamp = Date.now();
268
+ }
269
+ break;
270
+ }
271
+ const headerJson = Buffer.from(JSON.stringify(header), "utf8");
272
+ const headerLengthBuf = Buffer.alloc(4);
273
+ headerLengthBuf.writeUInt32BE(headerJson.length, 0);
274
+ const outputStream = (0, import_fs.createWriteStream)(outputPath);
275
+ outputStream.write(headerLengthBuf);
276
+ outputStream.write(headerJson);
277
+ const tempReadStream = (0, import_fs.createReadStream)(tempPath);
278
+ await (0, import_promises2.pipeline)(tempReadStream, outputStream);
279
+ console.log("\u2705 File encrypted successfully");
280
+ } finally {
281
+ await secureDelete(tempPath);
282
+ }
283
+ }
284
+ function encryptMessage(options, data) {
285
+ const isString = typeof data === "string";
286
+ const stringData = isString ? data : JSON.stringify(data);
287
+ const versionByte = Buffer.from([VERSION]);
288
+ const typeFlag = Buffer.from([isString ? 0 : 1]);
289
+ const iv = (0, import_crypto.randomBytes)(12);
290
+ const aesKey = (0, import_crypto.randomBytes)(32);
291
+ switch (options.type) {
292
+ case "symmetric-password":
293
+ validatePassword(options.password, options.strictMode);
294
+ const salt = (0, import_crypto.randomBytes)(16);
295
+ const key = (0, import_crypto.scryptSync)(options.password, salt, 32);
296
+ const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", key, iv);
297
+ const encrypted = Buffer.concat([
298
+ cipher.update(stringData, "utf8"),
299
+ cipher.final()
300
+ ]);
301
+ const tag = cipher.getAuthTag();
302
+ return Buffer.concat([
303
+ versionByte,
304
+ typeFlag,
305
+ salt,
306
+ iv,
307
+ tag,
308
+ encrypted
309
+ ]).toString("hex");
310
+ case "sealEnvelope":
311
+ validatePublicKey(options.recipientPublicKey, "rsa");
312
+ const cipherSeal = (0, import_crypto.createCipheriv)("aes-256-gcm", aesKey, iv);
313
+ const encryptedSeal = Buffer.concat([
314
+ cipherSeal.update(stringData, "utf8"),
315
+ cipherSeal.final()
316
+ ]);
317
+ const tagSeal = cipherSeal.getAuthTag();
318
+ const recipientPubKey = (0, import_crypto.createPublicKey)({
319
+ key: Buffer.from(options.recipientPublicKey, "base64"),
320
+ format: "der",
321
+ type: "spki"
322
+ });
323
+ const encryptedKey = (0, import_crypto.publicEncrypt)(
324
+ {
325
+ key: recipientPubKey,
326
+ // Use KeyObject instead of string
327
+ padding: import_crypto.constants.RSA_PKCS1_OAEP_PADDING,
328
+ oaepHash: "sha256"
329
+ },
330
+ aesKey
331
+ );
332
+ const keyLengthBuf = Buffer.alloc(2);
333
+ keyLengthBuf.writeUInt16BE(encryptedKey.length, 0);
334
+ return Buffer.concat([
335
+ versionByte,
336
+ typeFlag,
337
+ keyLengthBuf,
338
+ encryptedKey,
339
+ iv,
340
+ tagSeal,
341
+ encryptedSeal
342
+ ]).toString("hex");
343
+ case "secure-channel":
344
+ validatePublicKey(options.recipientPublicKey, "x25519");
345
+ const ephemeralData = deriveAESKeyForEncryption(
346
+ options.recipientPublicKey
347
+ );
348
+ let dataToEncrypt = stringData;
349
+ let hasTimestamp = false;
350
+ if (options.includeTimestamp !== false) {
351
+ const timestampBuf = createTimestampBuffer();
352
+ dataToEncrypt = Buffer.concat([
353
+ timestampBuf,
354
+ Buffer.from(stringData, "utf8")
355
+ ]).toString("base64");
356
+ hasTimestamp = true;
357
+ }
358
+ const cipherECDH = (0, import_crypto.createCipheriv)(
359
+ "aes-256-gcm",
360
+ ephemeralData.aesKey,
361
+ iv
362
+ );
363
+ const encryptedECDH = Buffer.concat([
364
+ cipherECDH.update(dataToEncrypt, "utf8"),
365
+ cipherECDH.final()
366
+ ]);
367
+ const tagECDH = cipherECDH.getAuthTag();
368
+ const ephemeralKeyBuffer = Buffer.from(
369
+ ephemeralData.ephemeralPublicKey,
370
+ "base64"
371
+ );
372
+ const ephemeralKeyLenBuf = Buffer.alloc(2);
373
+ ephemeralKeyLenBuf.writeUInt16BE(ephemeralKeyBuffer.length, 0);
374
+ const timestampFlag = Buffer.from([hasTimestamp ? 1 : 0]);
375
+ return Buffer.concat([
376
+ versionByte,
377
+ typeFlag,
378
+ timestampFlag,
379
+ ephemeralKeyLenBuf,
380
+ ephemeralKeyBuffer,
381
+ ephemeralData.salt,
382
+ iv,
383
+ tagECDH,
384
+ encryptedECDH
385
+ ]).toString("hex");
386
+ case "authenticated-channel":
387
+ validatePublicKey(options.recipientPublicKey, "x25519");
388
+ validatePrivateKey(options.senderPrivateKey, "ed25519");
389
+ const ephemeralAuthData = deriveAESKeyForEncryption(
390
+ options.recipientPublicKey
391
+ );
392
+ let dataToEncryptAuth = stringData;
393
+ let hasTimestampAuth = false;
394
+ if (options.includeTimestamp !== false) {
395
+ const timestampBuf = createTimestampBuffer();
396
+ dataToEncryptAuth = Buffer.concat([
397
+ timestampBuf,
398
+ Buffer.from(stringData, "utf8")
399
+ ]).toString("base64");
400
+ hasTimestampAuth = true;
401
+ }
402
+ const cipherAuth = (0, import_crypto.createCipheriv)(
403
+ "aes-256-gcm",
404
+ ephemeralAuthData.aesKey,
405
+ iv
406
+ );
407
+ const encryptedAuth = Buffer.concat([
408
+ cipherAuth.update(dataToEncryptAuth, "utf8"),
409
+ cipherAuth.final()
410
+ ]);
411
+ const tagAuth = cipherAuth.getAuthTag();
412
+ const senderPrivKey = (0, import_crypto.createPrivateKey)({
413
+ key: Buffer.from(options.senderPrivateKey, "base64"),
414
+ format: "der",
415
+ type: "pkcs8"
416
+ });
417
+ const ephemeralKeyBufferAuth = Buffer.from(
418
+ ephemeralAuthData.ephemeralPublicKey,
419
+ "base64"
420
+ );
421
+ const dataToSign = Buffer.concat([ephemeralKeyBufferAuth, iv, tagAuth]);
422
+ const signature = (0, import_crypto.sign)(null, dataToSign, senderPrivKey);
423
+ const ephemeralKeyLenBufAuth = Buffer.alloc(2);
424
+ ephemeralKeyLenBufAuth.writeUInt16BE(ephemeralKeyBufferAuth.length, 0);
425
+ const signatureLenBuf = Buffer.alloc(2);
426
+ signatureLenBuf.writeUInt16BE(signature.length, 0);
427
+ const timestampFlagAuth = Buffer.from([hasTimestampAuth ? 1 : 0]);
428
+ return Buffer.concat([
429
+ versionByte,
430
+ typeFlag,
431
+ timestampFlagAuth,
432
+ ephemeralKeyLenBufAuth,
433
+ ephemeralKeyBufferAuth,
434
+ signatureLenBuf,
435
+ signature,
436
+ ephemeralAuthData.salt,
437
+ iv,
438
+ tagAuth,
439
+ encryptedAuth
440
+ ]).toString("hex");
441
+ }
442
+ }
443
+ function deriveAESKeyForEncryption(recipientPublicKeyStr) {
444
+ const { publicKey, privateKey } = (0, import_crypto.generateKeyPairSync)("x25519");
445
+ const recipientPublicKey = (0, import_crypto.createPublicKey)({
446
+ key: Buffer.from(recipientPublicKeyStr, "base64"),
447
+ format: "der",
448
+ type: "spki"
449
+ });
450
+ const salt = (0, import_crypto.randomBytes)(16);
451
+ const sharedSecret = (0, import_crypto.diffieHellman)({
452
+ privateKey,
453
+ publicKey: recipientPublicKey
454
+ });
455
+ const aesKey = Buffer.from(
456
+ (0, import_crypto.hkdfSync)("sha256", sharedSecret, salt, "secure-channel-aes-key", 32)
457
+ );
458
+ return {
459
+ aesKey,
460
+ ephemeralPublicKey: publicKey.export({ type: "spki", format: "der" }).toString("base64"),
461
+ ephemeralPrivateKey: privateKey,
462
+ salt
463
+ };
464
+ }
465
+
466
+ // src/password/index.ts
467
+ var password_exports = {};
468
+ __export(password_exports, {
469
+ generatePassword: () => generatePassword,
470
+ hashPassword: () => hashPassword,
471
+ verifyPassword: () => verifyPassword
472
+ });
473
+
474
+ // src/password/generate.ts
475
+ var import_crypto2 = require("crypto");
476
+ var charsetMap = {
477
+ letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
478
+ numbers: "0123456789",
479
+ symbols: "!@#$%^&*()_+-=[]{}|;:,.<>?"
480
+ };
481
+ function generatePassword(lengthOrOptions) {
482
+ let length = 16;
483
+ let letters = true;
484
+ let numbers = true;
485
+ let symbols = true;
486
+ if (typeof lengthOrOptions === "number") {
487
+ length = lengthOrOptions;
488
+ } else if (typeof lengthOrOptions === "object") {
489
+ length = lengthOrOptions.length ?? 16;
490
+ letters = lengthOrOptions.letters ?? true;
491
+ numbers = lengthOrOptions.numbers ?? true;
492
+ symbols = lengthOrOptions.symbols ?? true;
493
+ }
494
+ let charset = "";
495
+ if (letters) charset += charsetMap.letters;
496
+ if (numbers) charset += charsetMap.numbers;
497
+ if (symbols) charset += charsetMap.symbols;
498
+ if (charset.length === 0) {
499
+ charset = Object.values(charsetMap).join("");
500
+ }
501
+ if (length < 1 || length > 1024) {
502
+ throw new Error("Length must be between 1 and 1024");
503
+ }
504
+ const bytes = (0, import_crypto2.randomBytes)(length);
505
+ const password = Array.from(
506
+ bytes,
507
+ (byte) => charset[byte % charset.length]
508
+ ).join("");
509
+ return password;
510
+ }
511
+
512
+ // src/password/hash.ts
513
+ var import_crypto3 = require("crypto");
514
+ var import_util = require("util");
515
+ var scryptAsync = (0, import_util.promisify)(import_crypto3.scrypt);
516
+ async function hashPassword(password) {
517
+ const salt = (0, import_crypto3.randomBytes)(16);
518
+ const derivedKey = await scryptAsync(password, salt, 64);
519
+ const saltBase64 = salt.toString("base64");
520
+ const hashBase64 = derivedKey.toString("base64");
521
+ return `scrypt$16$${saltBase64}$${hashBase64}`;
522
+ }
523
+
524
+ // src/password/verify.ts
525
+ var import_crypto4 = require("crypto");
526
+ var import_util2 = require("util");
527
+ var scryptAsync2 = (0, import_util2.promisify)(import_crypto4.scrypt);
528
+ async function scryptTyped(password, salt, keylen) {
529
+ const result = await scryptAsync2(password, salt, keylen);
530
+ if (!result) throw new Error("Scrypt derivation failed");
531
+ return result;
532
+ }
533
+ async function verifyPassword(password, storedHash) {
534
+ const [method, saltLengthStr, saltBase64, hashBase64] = storedHash.split("$");
535
+ if (method !== "scrypt") throw new Error("Unsupported hash method");
536
+ if (!saltBase64 || !hashBase64 || !saltLengthStr)
537
+ throw new Error("Invalid stored hash format");
538
+ const salt = Buffer.from(saltBase64, "base64");
539
+ const derivedKey = await scryptTyped(password, salt, 64);
540
+ const hashBuffer = Buffer.from(hashBase64, "base64");
541
+ if (derivedKey.length !== hashBuffer.length) return false;
542
+ let diff = 0;
543
+ for (let i = 0; i < derivedKey.length; i++) {
544
+ diff |= derivedKey[i] ^ hashBuffer[i];
545
+ }
546
+ return diff === 0;
547
+ }
548
+
549
+ // src/uuid/index.ts
550
+ var uuid_exports = {};
551
+ __export(uuid_exports, {
552
+ generateUUID: () => generateUUID
553
+ });
554
+
555
+ // src/uuid/generate.ts
556
+ var import_crypto5 = require("crypto");
557
+ function generateUUID() {
558
+ return (0, import_crypto5.randomUUID)();
559
+ }
560
+
561
+ // src/signature/index.ts
562
+ var signature_exports = {};
563
+ __export(signature_exports, {
564
+ Signer: () => Signer,
565
+ default: () => Signer,
566
+ envelope: () => envelope,
567
+ openEnvelope: () => openEnvelope,
568
+ sign: () => sign2,
569
+ verify: () => verify
570
+ });
571
+
572
+ // src/signature/sign.ts
573
+ var import_crypto6 = require("crypto");
574
+
575
+ // src/signature/serialize.ts
576
+ function canonicalStringify(obj) {
577
+ if (obj === null || typeof obj !== "object") {
578
+ return JSON.stringify(obj);
579
+ }
580
+ if (Array.isArray(obj)) {
581
+ return "[" + obj.map(canonicalStringify).join(",") + "]";
582
+ }
583
+ const keys = Object.keys(obj).sort();
584
+ const pairs = keys.map(
585
+ (key) => JSON.stringify(key) + ":" + canonicalStringify(obj[key])
586
+ );
587
+ return "{" + pairs.join(",") + "}";
588
+ }
589
+ function serialize(data, strategy, fields) {
590
+ switch (strategy) {
591
+ case "canonical":
592
+ return canonicalStringify(data);
593
+ case "raw":
594
+ return typeof data === "string" ? data : JSON.stringify(data);
595
+ case "selective":
596
+ if (!fields || fields.length === 0) {
597
+ throw new Error("Selective strategy requires fields parameter");
598
+ }
599
+ const selected = {};
600
+ for (const field of fields) {
601
+ if (field in data) {
602
+ selected[field] = data[field];
603
+ }
604
+ }
605
+ return canonicalStringify(selected);
606
+ default:
607
+ throw new Error(`Unknown strategy: ${strategy}`);
608
+ }
609
+ }
610
+
611
+ // src/signature/sign.ts
612
+ function parsePrivateKey(key) {
613
+ const keyObject = (0, import_crypto6.createPrivateKey)({
614
+ key: Buffer.from(key, "base64"),
615
+ format: "der",
616
+ type: "pkcs8"
617
+ });
618
+ if (keyObject.asymmetricKeyType !== "ed25519") {
619
+ throw new Error(`Expected ed25519 key, got ${keyObject.asymmetricKeyType}`);
620
+ }
621
+ return keyObject;
622
+ }
623
+ function sign2(data, privateKey, options) {
624
+ const keyObject = parsePrivateKey(privateKey);
625
+ const serialized = serialize(
626
+ data,
627
+ options?.strategy ?? "canonical",
628
+ options?.fields ?? []
629
+ );
630
+ return (0, import_crypto6.sign)(
631
+ null,
632
+ // ✅ Ed25519 requires null
633
+ Buffer.from(serialized),
634
+ keyObject
635
+ ).toString(options?.encoding ?? "base64");
636
+ }
637
+
638
+ // src/signature/verify.ts
639
+ var import_crypto7 = require("crypto");
640
+ function parsePublicKey(key) {
641
+ const keyObject = (0, import_crypto7.createPublicKey)({
642
+ key: Buffer.from(key, "base64"),
643
+ format: "der",
644
+ type: "spki"
645
+ });
646
+ if (keyObject.asymmetricKeyType !== "ed25519") {
647
+ throw new Error(`Expected ed25519 key, got ${keyObject.asymmetricKeyType}`);
648
+ }
649
+ return keyObject;
650
+ }
651
+ function verify(data, signature, publicKey, options) {
652
+ const keyObject = parsePublicKey(publicKey);
653
+ const serialized = serialize(
654
+ data,
655
+ options?.strategy ?? "canonical",
656
+ options?.fields ?? []
657
+ );
658
+ return (0, import_crypto7.verify)(
659
+ null,
660
+ // ✅ required for ed25519
661
+ Buffer.from(serialized),
662
+ keyObject,
663
+ Buffer.from(signature, options?.encoding ?? "base64")
664
+ );
665
+ }
666
+
667
+ // src/signature/index.ts
668
+ var Signer = class _Signer {
669
+ /**
670
+ * Creates a new Signer instance with optional default options.
671
+ *
672
+ * @param defaultOptions - Partial default options to override
673
+ * serialization strategy, fields, algorithm, encoding, or preHash.
674
+ */
675
+ constructor(defaultOptions) {
676
+ this.defaultOptions = {
677
+ strategy: defaultOptions?.strategy ?? "canonical",
678
+ fields: defaultOptions?.fields ?? [],
679
+ algorithm: defaultOptions?.algorithm ?? "SHA256",
680
+ encoding: defaultOptions?.encoding ?? "base64",
681
+ preHash: defaultOptions?.preHash ?? false
682
+ };
683
+ }
684
+ /**
685
+ * Sign data with a private key (static method).
686
+ *
687
+ * @param data - The data to sign.
688
+ * @param privateKey - The private key to use for signing.
689
+ * @param options - Optional signing options.
690
+ * @returns The digital signature as a string.
691
+ *
692
+ * @example
693
+ * ```ts
694
+ * const signature = Signer.sign({ message: "Hello" }, privateKey);
695
+ * ```
696
+ */
697
+ static sign(data, privateKey, options) {
698
+ const opts = {
699
+ strategy: options?.strategy ?? "canonical",
700
+ fields: options?.fields ?? [],
701
+ encoding: options?.encoding ?? "base64"
702
+ };
703
+ const signOpts = {
704
+ fields: opts.fields,
705
+ encoding: opts.encoding
706
+ };
707
+ if (opts.strategy === "canonical") {
708
+ signOpts.strategy = "canonical";
709
+ }
710
+ return sign2(data, privateKey, signOpts);
711
+ }
712
+ /**
713
+ * Verify a signature with a public key (static method).
714
+ *
715
+ * @param data - The original data.
716
+ * @param signature - The signature to verify.
717
+ * @param publicKey - The public key corresponding to the signer.
718
+ * @param options - Optional verification options.
719
+ * @returns `true` if the signature is valid, `false` otherwise.
720
+ *
721
+ * @example
722
+ * ```ts
723
+ * const isValid = Signer.verify({ message: "Hello" }, signature, publicKey);
724
+ * ```
725
+ */
726
+ static verify(data, signature, publicKey, options) {
727
+ const opts = {
728
+ strategy: options?.strategy ?? "canonical",
729
+ fields: options?.fields ?? [],
730
+ encoding: options?.encoding ?? "base64"
731
+ };
732
+ const verifyOpts = {
733
+ fields: opts.fields,
734
+ encoding: opts.encoding
735
+ };
736
+ if (opts.strategy === "canonical") {
737
+ verifyOpts.strategy = "canonical";
738
+ }
739
+ return verify(data, signature, publicKey, verifyOpts);
740
+ }
741
+ /**
742
+ * Create a signed envelope containing the data and its signature (static method).
743
+ *
744
+ * @param data - The data to include in the envelope.
745
+ * @param privateKey - The private key for signing.
746
+ * @param options - Optional signing options.
747
+ * @returns An object containing `{ data, signature }`.
748
+ *
749
+ * @example
750
+ * ```ts
751
+ * const envelope = Signer.envelope({ message: "Hello" }, privateKey);
752
+ * ```
753
+ */
754
+ static envelope(data, privateKey, options) {
755
+ return {
756
+ data,
757
+ signature: _Signer.sign(data, privateKey, options)
758
+ };
759
+ }
760
+ /**
761
+ * Verify and extract data from a signed envelope (static method).
762
+ *
763
+ * @param envelope - The envelope object `{ data, signature }`.
764
+ * @param publicKey - The public key to verify the signature.
765
+ * @param options - Optional verification options.
766
+ * @returns An object `{ valid, data }` indicating whether the signature is valid.
767
+ *
768
+ * @example
769
+ * ```ts
770
+ * const result = Signer.openEnvelope(envelope, publicKey);
771
+ * ```
772
+ */
773
+ static openEnvelope(envelope2, publicKey, options) {
774
+ const valid = _Signer.verify(
775
+ envelope2.data,
776
+ envelope2.signature,
777
+ publicKey,
778
+ options
779
+ );
780
+ return { valid, data: envelope2.data };
781
+ }
782
+ /**
783
+ * Sign data with a private key (instance method).
784
+ *
785
+ * @param data - The data to sign.
786
+ * @param privateKey - The private key to use for signing.
787
+ * @param options - Optional signing options.
788
+ * @returns The digital signature as a string.
789
+ *
790
+ * @example
791
+ * ```ts
792
+ * const signer = new Signer();
793
+ * const signature = signer.sign({ message: "Hello" }, privateKey);
794
+ * ```
795
+ */
796
+ sign(data, privateKey, options) {
797
+ const opts = { ...this.defaultOptions, ...options };
798
+ const signOpts = {
799
+ fields: opts.fields,
800
+ encoding: opts.encoding
801
+ };
802
+ if (opts.strategy === "canonical") {
803
+ signOpts.strategy = "canonical";
804
+ }
805
+ return sign2(data, privateKey, signOpts);
806
+ }
807
+ /**
808
+ * Verify a signature with a public key (instance method).
809
+ *
810
+ * @param data - The original data.
811
+ * @param signature - The signature to verify.
812
+ * @param publicKey - The public key corresponding to the signer.
813
+ * @param options - Optional verification options.
814
+ * @returns `true` if the signature is valid, `false` otherwise.
815
+ *
816
+ * @example
817
+ * ```ts
818
+ * const isValid = signer.verify({ message: "Hello" }, signature, publicKey);
819
+ * ```
820
+ */
821
+ verify(data, signature, publicKey, options) {
822
+ const opts = { ...this.defaultOptions, ...options };
823
+ const verifyOpts = {
824
+ fields: opts.fields,
825
+ encoding: opts.encoding
826
+ };
827
+ if (opts.strategy === "canonical") {
828
+ verifyOpts.strategy = "canonical";
829
+ }
830
+ return verify(data, signature, publicKey, verifyOpts);
831
+ }
832
+ /**
833
+ * Create a signed envelope containing the data and its signature (instance method).
834
+ *
835
+ * @param data - The data to include in the envelope.
836
+ * @param privateKey - The private key for signing.
837
+ * @param options - Optional signing options.
838
+ * @returns An object containing `{ data, signature }`.
839
+ *
840
+ * @example
841
+ * ```ts
842
+ * const envelope = signer.envelope({ message: "Hello" }, privateKey);
843
+ * ```
844
+ */
845
+ envelope(data, privateKey, options) {
846
+ return {
847
+ data,
848
+ signature: this.sign(data, privateKey, options)
849
+ };
850
+ }
851
+ /**
852
+ * Verify and extract data from a signed envelope (instance method).
853
+ *
854
+ * @param envelope - The envelope object `{ data, signature }`.
855
+ * @param publicKey - The public key to verify the signature.
856
+ * @param options - Optional verification options.
857
+ * @returns An object `{ valid, data }` indicating whether the signature is valid.
858
+ *
859
+ * @example
860
+ * ```ts
861
+ * const result = signer.openEnvelope(envelope, publicKey);
862
+ * ```
863
+ */
864
+ openEnvelope(envelope2, publicKey, options) {
865
+ const valid = this.verify(
866
+ envelope2.data,
867
+ envelope2.signature,
868
+ publicKey,
869
+ options
870
+ );
871
+ return { valid, data: envelope2.data };
872
+ }
873
+ };
874
+ var defaultSigner = new Signer();
875
+ var envelope = defaultSigner.envelope.bind(defaultSigner);
876
+ var openEnvelope = defaultSigner.openEnvelope.bind(defaultSigner);
877
+
878
+ // src/hash/index.ts
879
+ var hash_exports = {};
880
+ __export(hash_exports, {
881
+ hash: () => hash,
882
+ hashHmac: () => hashHmac,
883
+ verifyHmac: () => verifyHmac
884
+ });
885
+
886
+ // src/hash/hash.ts
887
+ var import_crypto8 = require("crypto");
888
+ function hash(data) {
889
+ const hash2 = (0, import_crypto8.createHash)("sha256");
890
+ hash2.update(data);
891
+ return hash2.digest("hex");
892
+ }
893
+
894
+ // src/hash/hashHmac.ts
895
+ var import_crypto9 = require("crypto");
896
+ function hashHmac(secret, data) {
897
+ return (0, import_crypto9.createHmac)("sha256", secret).update(data).digest("hex");
898
+ }
899
+
900
+ // src/hash/verifyHmac.ts
901
+ var import_crypto10 = require("crypto");
902
+ function verifyHmac(secret, data, expectedHex) {
903
+ const actual = (0, import_crypto10.createHmac)("sha256", secret).update(data).digest();
904
+ const expected = Buffer.from(expectedHex, "hex");
905
+ if (actual.length !== expected.length) {
906
+ return false;
907
+ }
908
+ return (0, import_crypto10.timingSafeEqual)(actual, expected);
909
+ }
910
+
911
+ // src/keys/index.ts
912
+ var keys_exports = {};
913
+ __export(keys_exports, {
914
+ Key: () => Key,
915
+ generateECDHKeyPair: () => generateECDHKeyPair,
916
+ generateRSAKeyPair: () => generateRSAKeyPair
917
+ });
918
+
919
+ // src/keys/rsa.ts
920
+ var import_crypto11 = require("crypto");
921
+ function generateRSAKeyPair() {
922
+ return new Promise((resolve, reject) => {
923
+ (0, import_crypto11.generateKeyPair)(
924
+ "rsa",
925
+ {
926
+ modulusLength: 2048,
927
+ publicKeyEncoding: {
928
+ type: "spki",
929
+ format: "der"
930
+ // Changed from "pem" to "der"
931
+ },
932
+ privateKeyEncoding: {
933
+ type: "pkcs8",
934
+ format: "der"
935
+ // Changed from "pem" to "der"
936
+ }
937
+ },
938
+ (err, publicKey, privateKey) => {
939
+ if (err) return reject(err);
940
+ resolve({
941
+ publicKey: publicKey.toString("base64"),
942
+ privateKey: privateKey.toString("base64")
943
+ });
944
+ }
945
+ );
946
+ });
947
+ }
948
+
949
+ // src/keys/ed25519.ts
950
+ var import_crypto12 = require("crypto");
951
+ function generateEd25519KeyPair() {
952
+ const { publicKey, privateKey } = (0, import_crypto12.generateKeyPairSync)("ed25519", {
953
+ publicKeyEncoding: {
954
+ type: "spki",
955
+ format: "der"
956
+ },
957
+ privateKeyEncoding: {
958
+ type: "pkcs8",
959
+ format: "der"
960
+ }
961
+ });
962
+ return {
963
+ publicKey: publicKey.toString("base64"),
964
+ privateKey: privateKey.toString("base64")
965
+ };
966
+ }
967
+
968
+ // src/keys/x25519.ts
969
+ var import_crypto13 = require("crypto");
970
+ function generateX25519KeyPair() {
971
+ const { publicKey, privateKey } = (0, import_crypto13.generateKeyPairSync)("x25519", {
972
+ publicKeyEncoding: {
973
+ type: "spki",
974
+ format: "der"
975
+ },
976
+ privateKeyEncoding: {
977
+ type: "pkcs8",
978
+ format: "der"
979
+ }
980
+ });
981
+ return {
982
+ publicKey: publicKey.toString("base64"),
983
+ privateKey: privateKey.toString("base64")
984
+ };
985
+ }
986
+
987
+ // src/keys/authenticated.ts
988
+ function generateAuthenticatedKeySet() {
989
+ return {
990
+ encryption: generateX25519KeyPair(),
991
+ signing: generateEd25519KeyPair()
992
+ };
993
+ }
994
+
995
+ // src/keys/ecdh.ts
996
+ var import_crypto14 = require("crypto");
997
+ function generateECDHKeyPair() {
998
+ const { publicKey, privateKey } = (0, import_crypto14.generateKeyPairSync)("x25519");
999
+ return {
1000
+ publicKey: publicKey.export({ type: "spki", format: "der" }).toString("base64"),
1001
+ privateKey: privateKey.export({ type: "pkcs8", format: "der" }).toString("base64")
1002
+ };
1003
+ }
1004
+
1005
+ // src/keys/index.ts
1006
+ var Key = class _Key {
1007
+ /**
1008
+ * Generates a new Key instance for the specified `keyType`.
1009
+ *
1010
+ * @param key - The type of key to generate:
1011
+ * - `"seal"`: RSA key pair for encryption/signing
1012
+ * - `"sign"`: Ed25519 key pair for signing
1013
+ * - `"secure-channel"`: X25519 key pair for ECDH (secure channel)
1014
+ * - `"authenticated-channel"`: Combined X25519 + Ed25519 key pair
1015
+ *
1016
+ * @returns A Promise that resolves to a `Key` instance with the generated keys.
1017
+ *
1018
+ * @example
1019
+ * ```ts
1020
+ * import { Key } from "./key";
1021
+ *
1022
+ * async function main() {
1023
+ * const sealKey = await Key.generate("seal");
1024
+ * console.log(sealKey.publicKey);
1025
+ * console.log(sealKey.privateKey);
1026
+ *
1027
+ * const authKey = await Key.generate("authenticated-channel");
1028
+ * console.log(authKey.publicKey); // Encryption key
1029
+ * console.log(authKey.signingPublicKey); // Signing key
1030
+ * }
1031
+ *
1032
+ * main();
1033
+ * ```
1034
+ */
1035
+ static async generate(key) {
1036
+ const k = new _Key();
1037
+ switch (key) {
1038
+ case "authenticated-channel": {
1039
+ const key2 = generateAuthenticatedKeySet();
1040
+ k.publicKey = key2.encryption.publicKey;
1041
+ k.privateKey = key2.encryption.privateKey;
1042
+ k.signingPublicKey = key2.signing.publicKey;
1043
+ k.signingPrivateKey = key2.signing.privateKey;
1044
+ break;
1045
+ }
1046
+ case "secure-channel": {
1047
+ const { publicKey, privateKey } = generateX25519KeyPair();
1048
+ k.publicKey = publicKey;
1049
+ k.privateKey = privateKey;
1050
+ break;
1051
+ }
1052
+ case "seal": {
1053
+ const { publicKey, privateKey } = await generateRSAKeyPair();
1054
+ k.publicKey = publicKey;
1055
+ k.privateKey = privateKey;
1056
+ break;
1057
+ }
1058
+ case "sign": {
1059
+ const { publicKey, privateKey } = generateEd25519KeyPair();
1060
+ k.publicKey = publicKey;
1061
+ k.privateKey = privateKey;
1062
+ break;
1063
+ }
1064
+ default:
1065
+ throw new Error(`Unknown key type: ${key}`);
1066
+ }
1067
+ return k;
1068
+ }
1069
+ };
1070
+
1071
+ // src/otp/index.ts
1072
+ var otp_exports = {};
1073
+ __export(otp_exports, {
1074
+ generateOTP: () => generateOTP,
1075
+ generateTOTP: () => generateTOTP
1076
+ });
1077
+
1078
+ // src/otp/totp.ts
1079
+ var import_crypto15 = require("crypto");
1080
+ function base32ToBuffer(base32) {
1081
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
1082
+ let bits = "";
1083
+ let bytes = [];
1084
+ base32 = base32.replace(/=+$/, "").toUpperCase();
1085
+ for (const char of base32) {
1086
+ const val = alphabet.indexOf(char);
1087
+ bits += val.toString(2).padStart(5, "0");
1088
+ }
1089
+ for (let i = 0; i + 8 <= bits.length; i += 8) {
1090
+ bytes.push(parseInt(bits.substring(i, i + 8), 2));
1091
+ }
1092
+ return Buffer.from(bytes);
1093
+ }
1094
+ function generateTOTP(secret, digits = 6, period = 30, timestamp = Date.now()) {
1095
+ const key = base32ToBuffer(secret);
1096
+ let counter = Math.floor(timestamp / 1e3 / period);
1097
+ const buffer = Buffer.alloc(8);
1098
+ for (let i = 7; i >= 0; i--) {
1099
+ buffer[i] = counter & 255;
1100
+ counter >>= 8;
1101
+ }
1102
+ const hmac = (0, import_crypto15.createHmac)("sha1", key).update(buffer).digest();
1103
+ const offset = hmac[hmac.length - 1] & 15;
1104
+ const code = (hmac[offset] & 127) << 24 | (hmac[offset + 1] & 255) << 16 | (hmac[offset + 2] & 255) << 8 | hmac[offset + 3] & 255;
1105
+ return (code % 10 ** digits).toString().padStart(digits, "0");
1106
+ }
1107
+
1108
+ // src/otp/otp.ts
1109
+ var import_crypto16 = require("crypto");
1110
+ function generateOTP(length = 6) {
1111
+ const max = 10 ** length;
1112
+ const randomNumber = parseInt((0, import_crypto16.randomBytes)(4).toString("hex"), 16) % max;
1113
+ return randomNumber.toString().padStart(length, "0");
1114
+ }
1115
+
1116
+ // src/crypto/decrypt.ts
1117
+ var import_fs2 = require("fs");
1118
+ var import_crypto17 = require("crypto");
1119
+ var import_promises3 = require("stream/promises");
1120
+ function validateTimestamp(timestamp, maxAge = MESSAGE_MAX_AGE_MS) {
1121
+ const now = Date.now();
1122
+ const age = now - timestamp;
1123
+ if (age < 0) {
1124
+ throw new Error(
1125
+ "Message timestamp is in the future - possible clock skew or attack"
1126
+ );
1127
+ }
1128
+ if (age > maxAge) {
1129
+ throw new Error(
1130
+ `Message expired (age: ${Math.floor(age / 1e3)}s, max: ${Math.floor(
1131
+ maxAge / 1e3
1132
+ )}s) - possible replay attack`
1133
+ );
1134
+ }
1135
+ }
1136
+ function validateVersion(version) {
1137
+ if (version !== VERSION) {
1138
+ throw new Error(
1139
+ `Unsupported format version: ${version} (expected: ${VERSION})`
1140
+ );
1141
+ }
1142
+ }
1143
+ async function decrypt(options, data, inputPath, outputPath) {
1144
+ if (!data && !inputPath) {
1145
+ throw new Error("No data to decrypt");
1146
+ }
1147
+ if (options.strictMode) {
1148
+ console.log("\u{1F512} Strict mode enabled - all security checks active");
1149
+ }
1150
+ const isFile = inputPath && outputPath;
1151
+ if (isFile) {
1152
+ await decryptFile(options, inputPath, outputPath);
1153
+ return { type: "file", outputPath };
1154
+ } else {
1155
+ const encryptedHex = typeof data === "string" ? data : data.toString("hex");
1156
+ const result = decryptMessage(options, encryptedHex);
1157
+ return {
1158
+ type: "message",
1159
+ data: result.data,
1160
+ metadata: result.metadata
1161
+ };
1162
+ }
1163
+ }
1164
+ async function decryptFile(options, inputPath, outputPath) {
1165
+ async function readFileHeader(filePath) {
1166
+ return new Promise((resolve, reject) => {
1167
+ const stream = (0, import_fs2.createReadStream)(filePath, { start: 0 });
1168
+ const chunks = [];
1169
+ let bytesRead = 0;
1170
+ let headerLength = 0;
1171
+ let headerBuffer = null;
1172
+ stream.on("data", (chunk) => {
1173
+ chunks.push(chunk);
1174
+ bytesRead += chunk.length;
1175
+ if (bytesRead >= 4 && headerLength === 0) {
1176
+ const allData = Buffer.concat(chunks);
1177
+ headerLength = allData.readUInt32BE(0);
1178
+ if (bytesRead >= 4 + headerLength) {
1179
+ headerBuffer = allData.subarray(4, 4 + headerLength);
1180
+ stream.destroy();
1181
+ }
1182
+ }
1183
+ });
1184
+ stream.on("close", () => {
1185
+ if (!headerBuffer) return reject(new Error("Could not read header"));
1186
+ const headerJson = headerBuffer.toString("utf8");
1187
+ const header2 = JSON.parse(headerJson);
1188
+ validateVersion(header2.version);
1189
+ const encryptedDataOffset2 = 4 + headerLength;
1190
+ resolve({ header: header2, encryptedDataOffset: encryptedDataOffset2 });
1191
+ });
1192
+ stream.on("error", reject);
1193
+ });
1194
+ }
1195
+ const { header, encryptedDataOffset } = await readFileHeader(inputPath);
1196
+ if (header.timestamp) {
1197
+ const shouldValidate = options.type === "secure-channel" && options.validateTimestamp !== false || options.type === "authenticated-channel" && options.validateTimestamp !== false || options.strictMode;
1198
+ if (shouldValidate) {
1199
+ validateTimestamp(header.timestamp);
1200
+ }
1201
+ }
1202
+ await decryptFileStreaming(
1203
+ options,
1204
+ inputPath,
1205
+ outputPath,
1206
+ header,
1207
+ encryptedDataOffset
1208
+ );
1209
+ }
1210
+ async function decryptFileStreaming(options, inputPath, outputPath, header, dataOffset) {
1211
+ const iv = Buffer.from(header.iv, "base64");
1212
+ const authTag = Buffer.from(header.authTag, "base64");
1213
+ let decipher;
1214
+ switch (options.type) {
1215
+ case "symmetric-password":
1216
+ if (!options.password) {
1217
+ throw new Error("Password required for symmetric decryption");
1218
+ }
1219
+ if (!header.salt) {
1220
+ throw new Error("Salt missing from encrypted file");
1221
+ }
1222
+ const salt = Buffer.from(header.salt, "base64");
1223
+ const key = (0, import_crypto17.scryptSync)(options.password, salt, 32);
1224
+ decipher = (0, import_crypto17.createDecipheriv)("aes-256-gcm", key, iv);
1225
+ decipher.setAuthTag(authTag);
1226
+ break;
1227
+ case "openEnvelope":
1228
+ if (!options.recipientPrivateKey) {
1229
+ throw new Error("Recipient private key required for decryption");
1230
+ }
1231
+ if (!header.encryptedKey) {
1232
+ throw new Error("Encrypted key missing from file header");
1233
+ }
1234
+ const encryptedAESKey = Buffer.from(header.encryptedKey, "base64");
1235
+ const recipientPrivKey = (0, import_crypto17.createPrivateKey)({
1236
+ key: Buffer.from(options.recipientPrivateKey, "base64"),
1237
+ format: "der",
1238
+ type: "pkcs8"
1239
+ });
1240
+ const aesKey = (0, import_crypto17.privateDecrypt)(
1241
+ {
1242
+ key: recipientPrivKey,
1243
+ // Use KeyObject instead of string
1244
+ padding: import_crypto17.constants.RSA_PKCS1_OAEP_PADDING,
1245
+ oaepHash: "sha256"
1246
+ },
1247
+ encryptedAESKey
1248
+ );
1249
+ decipher = (0, import_crypto17.createDecipheriv)("aes-256-gcm", aesKey, iv);
1250
+ decipher.setAuthTag(authTag);
1251
+ break;
1252
+ case "secure-channel":
1253
+ if (!options.recipientPrivateKey) {
1254
+ throw new Error("Recipient private key required for secure channel");
1255
+ }
1256
+ if (!header.ephemeralPublicKey || !header.salt) {
1257
+ throw new Error("Ephemeral public key or salt missing from header");
1258
+ }
1259
+ const sharedSecret = deriveAESKeyForDecryption(
1260
+ options.recipientPrivateKey,
1261
+ header.ephemeralPublicKey,
1262
+ Buffer.from(header.salt, "base64")
1263
+ );
1264
+ decipher = (0, import_crypto17.createDecipheriv)("aes-256-gcm", sharedSecret, iv);
1265
+ decipher.setAuthTag(authTag);
1266
+ break;
1267
+ case "authenticated-channel":
1268
+ if (!options.recipientPrivateKey) {
1269
+ throw new Error(
1270
+ "Recipient private key required for authenticated channel"
1271
+ );
1272
+ }
1273
+ if (!options.senderPublicKey) {
1274
+ throw new Error(
1275
+ "Sender public key required for signature verification"
1276
+ );
1277
+ }
1278
+ if (!header.ephemeralPublicKey || !header.salt || !header.signature) {
1279
+ throw new Error(
1280
+ "Ephemeral key, salt, or signature missing from header"
1281
+ );
1282
+ }
1283
+ const senderPubKey = (0, import_crypto17.createPublicKey)({
1284
+ key: Buffer.from(options.senderPublicKey, "base64"),
1285
+ format: "der",
1286
+ type: "spki"
1287
+ });
1288
+ const dataToVerify = Buffer.concat([
1289
+ Buffer.from(header.ephemeralPublicKey, "base64"),
1290
+ iv,
1291
+ authTag
1292
+ ]);
1293
+ const signatureValid = (0, import_crypto17.verify)(
1294
+ null,
1295
+ dataToVerify,
1296
+ senderPubKey,
1297
+ Buffer.from(header.signature, "base64")
1298
+ );
1299
+ if (!signatureValid) {
1300
+ throw new Error("Invalid signature - message tampered or wrong sender");
1301
+ }
1302
+ const sharedSecretAuth = deriveAESKeyForDecryption(
1303
+ options.recipientPrivateKey,
1304
+ header.ephemeralPublicKey,
1305
+ Buffer.from(header.salt, "base64")
1306
+ );
1307
+ decipher = (0, import_crypto17.createDecipheriv)("aes-256-gcm", sharedSecretAuth, iv);
1308
+ decipher.setAuthTag(authTag);
1309
+ break;
1310
+ }
1311
+ const inputStream = (0, import_fs2.createReadStream)(inputPath, { start: dataOffset });
1312
+ const outputStream = (0, import_fs2.createWriteStream)(outputPath);
1313
+ await (0, import_promises3.pipeline)(inputStream, decipher, outputStream);
1314
+ console.log("\u2705 File decrypted successfully");
1315
+ }
1316
+ function decryptMessage(options, encryptedHex) {
1317
+ const buffer = Buffer.from(encryptedHex, "hex");
1318
+ let offset = 0;
1319
+ const version = buffer[offset];
1320
+ if (!version) throw new Error("Missing Version data, can't decrypt");
1321
+ validateVersion(version);
1322
+ offset += 1;
1323
+ const typeFlag = buffer[offset];
1324
+ const isString = typeFlag === 0;
1325
+ offset += 1;
1326
+ let decryptedData;
1327
+ let metadata = {};
1328
+ switch (options.type) {
1329
+ case "symmetric-password":
1330
+ if (!options.password) {
1331
+ throw new Error("Password required for symmetric decryption");
1332
+ }
1333
+ const salt = buffer.subarray(offset, offset + 16);
1334
+ offset += 16;
1335
+ const ivSymmetric = buffer.subarray(offset, offset + 12);
1336
+ offset += 12;
1337
+ const tagSymmetric = buffer.subarray(offset, offset + 16);
1338
+ offset += 16;
1339
+ const encryptedSymmetric = buffer.subarray(offset);
1340
+ const key = (0, import_crypto17.scryptSync)(options.password, salt, 32);
1341
+ const decipherSymmetric = (0, import_crypto17.createDecipheriv)(
1342
+ "aes-256-gcm",
1343
+ key,
1344
+ ivSymmetric
1345
+ );
1346
+ decipherSymmetric.setAuthTag(tagSymmetric);
1347
+ decryptedData = Buffer.concat([
1348
+ decipherSymmetric.update(encryptedSymmetric),
1349
+ decipherSymmetric.final()
1350
+ ]).toString("utf8");
1351
+ break;
1352
+ case "openEnvelope":
1353
+ if (!options.recipientPrivateKey) {
1354
+ throw new Error("Recipient private key required for decryption");
1355
+ }
1356
+ const encryptedKeyLength = buffer.readUInt16BE(offset);
1357
+ offset += 2;
1358
+ const encryptedKey = buffer.subarray(offset, offset + encryptedKeyLength);
1359
+ offset += encryptedKeyLength;
1360
+ const ivRSA = buffer.subarray(offset, offset + 12);
1361
+ offset += 12;
1362
+ const tagRSA = buffer.subarray(offset, offset + 16);
1363
+ offset += 16;
1364
+ const encryptedRSA = buffer.subarray(offset);
1365
+ const recipientPrivKey = (0, import_crypto17.createPrivateKey)({
1366
+ key: Buffer.from(options.recipientPrivateKey, "base64"),
1367
+ format: "der",
1368
+ type: "pkcs8"
1369
+ });
1370
+ const aesKey = (0, import_crypto17.privateDecrypt)(
1371
+ {
1372
+ key: recipientPrivKey,
1373
+ // Use KeyObject instead of string
1374
+ padding: import_crypto17.constants.RSA_PKCS1_OAEP_PADDING,
1375
+ oaepHash: "sha256"
1376
+ },
1377
+ encryptedKey
1378
+ );
1379
+ const decipherRSA = (0, import_crypto17.createDecipheriv)("aes-256-gcm", aesKey, ivRSA);
1380
+ decipherRSA.setAuthTag(tagRSA);
1381
+ decryptedData = Buffer.concat([
1382
+ decipherRSA.update(encryptedRSA),
1383
+ decipherRSA.final()
1384
+ ]).toString("utf8");
1385
+ break;
1386
+ case "secure-channel":
1387
+ if (!options.recipientPrivateKey) {
1388
+ throw new Error("Recipient private key required for secure channel");
1389
+ }
1390
+ const hasTimestamp = buffer[offset] === 1;
1391
+ offset += 1;
1392
+ const ephemeralKeyLength = buffer.readUInt16BE(offset);
1393
+ offset += 2;
1394
+ const ephemeralPublicKey = buffer.subarray(
1395
+ offset,
1396
+ offset + ephemeralKeyLength
1397
+ );
1398
+ offset += ephemeralKeyLength;
1399
+ const saltECDH = buffer.subarray(offset, offset + 16);
1400
+ offset += 16;
1401
+ const ivECDH = buffer.subarray(offset, offset + 12);
1402
+ offset += 12;
1403
+ const tagECDH = buffer.subarray(offset, offset + 16);
1404
+ offset += 16;
1405
+ const encryptedECDH = buffer.subarray(offset);
1406
+ const sharedSecret = deriveAESKeyForDecryption(
1407
+ options.recipientPrivateKey,
1408
+ ephemeralPublicKey.toString("base64"),
1409
+ saltECDH
1410
+ );
1411
+ const decipherECDH = (0, import_crypto17.createDecipheriv)(
1412
+ "aes-256-gcm",
1413
+ sharedSecret,
1414
+ ivECDH
1415
+ );
1416
+ decipherECDH.setAuthTag(tagECDH);
1417
+ let decryptedBuffer = Buffer.concat([
1418
+ decipherECDH.update(encryptedECDH),
1419
+ decipherECDH.final()
1420
+ ]);
1421
+ if (hasTimestamp) {
1422
+ const decryptedBase64 = decryptedBuffer.toString("utf8");
1423
+ const fullBuffer = Buffer.from(decryptedBase64, "base64");
1424
+ const timestamp = Number(fullBuffer.readBigUInt64BE(0));
1425
+ metadata.timestamp = timestamp;
1426
+ if (options.validateTimestamp !== false || options.strictMode) {
1427
+ validateTimestamp(timestamp);
1428
+ }
1429
+ decryptedData = fullBuffer.subarray(8).toString("utf8");
1430
+ } else {
1431
+ decryptedData = decryptedBuffer.toString("utf8");
1432
+ }
1433
+ break;
1434
+ case "authenticated-channel":
1435
+ if (!options.recipientPrivateKey) {
1436
+ throw new Error(
1437
+ "Recipient private key required for authenticated channel"
1438
+ );
1439
+ }
1440
+ if (!options.senderPublicKey) {
1441
+ throw new Error(
1442
+ "Sender public key required for signature verification"
1443
+ );
1444
+ }
1445
+ const hasTimestampAuth = buffer[offset] === 1;
1446
+ offset += 1;
1447
+ const ephemeralKeyLengthAuth = buffer.readUInt16BE(offset);
1448
+ offset += 2;
1449
+ const ephemeralPublicKeyAuth = buffer.subarray(
1450
+ offset,
1451
+ offset + ephemeralKeyLengthAuth
1452
+ );
1453
+ offset += ephemeralKeyLengthAuth;
1454
+ const signatureLength = buffer.readUInt16BE(offset);
1455
+ offset += 2;
1456
+ const signature = buffer.subarray(offset, offset + signatureLength);
1457
+ offset += signatureLength;
1458
+ const saltAuth = buffer.subarray(offset, offset + 16);
1459
+ offset += 16;
1460
+ const ivAuth = buffer.subarray(offset, offset + 12);
1461
+ offset += 12;
1462
+ const tagAuth = buffer.subarray(offset, offset + 16);
1463
+ offset += 16;
1464
+ const encryptedAuth = buffer.subarray(offset);
1465
+ const senderPubKey = (0, import_crypto17.createPublicKey)({
1466
+ key: Buffer.from(options.senderPublicKey, "base64"),
1467
+ format: "der",
1468
+ type: "spki"
1469
+ });
1470
+ const dataToVerify = Buffer.concat([
1471
+ ephemeralPublicKeyAuth,
1472
+ ivAuth,
1473
+ tagAuth
1474
+ ]);
1475
+ const signatureValid = (0, import_crypto17.verify)(
1476
+ null,
1477
+ dataToVerify,
1478
+ senderPubKey,
1479
+ signature
1480
+ );
1481
+ if (!signatureValid) {
1482
+ throw new Error("Invalid signature - message tampered or wrong sender");
1483
+ }
1484
+ metadata.authenticated = true;
1485
+ const sharedSecretAuth = deriveAESKeyForDecryption(
1486
+ options.recipientPrivateKey,
1487
+ ephemeralPublicKeyAuth.toString("base64"),
1488
+ saltAuth
1489
+ );
1490
+ const decipherAuth = (0, import_crypto17.createDecipheriv)(
1491
+ "aes-256-gcm",
1492
+ sharedSecretAuth,
1493
+ ivAuth
1494
+ );
1495
+ decipherAuth.setAuthTag(tagAuth);
1496
+ let decryptedBufferAuth = Buffer.concat([
1497
+ decipherAuth.update(encryptedAuth),
1498
+ decipherAuth.final()
1499
+ ]);
1500
+ if (hasTimestampAuth) {
1501
+ const decryptedBase64Auth = decryptedBufferAuth.toString("utf8");
1502
+ const fullBufferAuth = Buffer.from(decryptedBase64Auth, "base64");
1503
+ const timestampAuth = Number(fullBufferAuth.readBigUInt64BE(0));
1504
+ metadata.timestamp = timestampAuth;
1505
+ if (options.validateTimestamp !== false || options.strictMode) {
1506
+ validateTimestamp(timestampAuth);
1507
+ }
1508
+ decryptedData = fullBufferAuth.subarray(8).toString("utf8");
1509
+ } else {
1510
+ decryptedData = decryptedBufferAuth.toString("utf8");
1511
+ }
1512
+ break;
1513
+ }
1514
+ const finalData = isString ? decryptedData : JSON.parse(decryptedData);
1515
+ return { data: finalData, metadata };
1516
+ }
1517
+ function deriveAESKeyForDecryption(recipientPrivateKeyStr, ephemeralPublicKeyStr, salt) {
1518
+ const recipientPrivateKey = (0, import_crypto17.createPrivateKey)({
1519
+ key: Buffer.from(recipientPrivateKeyStr, "base64"),
1520
+ format: "der",
1521
+ type: "pkcs8"
1522
+ });
1523
+ const ephemeralPublicKey = (0, import_crypto17.createPublicKey)({
1524
+ key: Buffer.from(ephemeralPublicKeyStr, "base64"),
1525
+ format: "der",
1526
+ type: "spki"
1527
+ });
1528
+ const sharedSecret = (0, import_crypto17.diffieHellman)({
1529
+ privateKey: recipientPrivateKey,
1530
+ publicKey: ephemeralPublicKey
1531
+ });
1532
+ const aesKey = Buffer.from(
1533
+ (0, import_crypto17.hkdfSync)("sha256", sharedSecret, salt, "secure-channel-aes-key", 32)
1534
+ );
1535
+ return aesKey;
1536
+ }
1537
+
1538
+ // src/index.ts
1539
+ var LIBRARY_VERSION = VERSION;
1540
+ var MINIMUM_PASSWORD_LENGTH = MIN_PASSWORD_LENGTH;
1541
+ var MAX_MESSAGE_AGE = MESSAGE_MAX_AGE_MS;
1542
+ // Annotate the CommonJS export names for ESM import in node:
1543
+ 0 && (module.exports = {
1544
+ LIBRARY_VERSION,
1545
+ MAX_MESSAGE_AGE,
1546
+ MESSAGE_MAX_AGE_MS,
1547
+ MINIMUM_PASSWORD_LENGTH,
1548
+ MIN_PASSWORD_LENGTH,
1549
+ VERSION,
1550
+ decrypt,
1551
+ decryptFile,
1552
+ decryptMessage,
1553
+ deriveAESKeyForDecryption,
1554
+ deriveAESKeyForEncryption,
1555
+ encrypt,
1556
+ encryptFileStreaming,
1557
+ encryptMessage,
1558
+ hash,
1559
+ keys,
1560
+ otp,
1561
+ password,
1562
+ signature,
1563
+ uuid,
1564
+ validatePassword,
1565
+ validatePrivateKey,
1566
+ validatePublicKey,
1567
+ validateTimestamp,
1568
+ validateVersion
1569
+ });