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