@msdis/shield 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE +140 -0
  2. package/README.md +106 -0
  3. package/dist/aead/index.d.ts +37 -0
  4. package/dist/aead/index.js +7 -0
  5. package/dist/aead/index.js.map +1 -0
  6. package/dist/asymmetric/index.d.ts +32 -0
  7. package/dist/asymmetric/index.js +6 -0
  8. package/dist/asymmetric/index.js.map +1 -0
  9. package/dist/chunk-3DQPQCAR.js +114 -0
  10. package/dist/chunk-3DQPQCAR.js.map +1 -0
  11. package/dist/chunk-3HCT6A2P.js +55 -0
  12. package/dist/chunk-3HCT6A2P.js.map +1 -0
  13. package/dist/chunk-AB2WZ7Y2.js +57 -0
  14. package/dist/chunk-AB2WZ7Y2.js.map +1 -0
  15. package/dist/chunk-BUFRR5PB.js +9 -0
  16. package/dist/chunk-BUFRR5PB.js.map +1 -0
  17. package/dist/chunk-CYIGDF63.js +30 -0
  18. package/dist/chunk-CYIGDF63.js.map +1 -0
  19. package/dist/chunk-EOXWR7DS.js +153 -0
  20. package/dist/chunk-EOXWR7DS.js.map +1 -0
  21. package/dist/chunk-FUDDBD2G.js +43 -0
  22. package/dist/chunk-FUDDBD2G.js.map +1 -0
  23. package/dist/chunk-JSKIWIEC.js +56 -0
  24. package/dist/chunk-JSKIWIEC.js.map +1 -0
  25. package/dist/chunk-JVFP2GAO.js +66 -0
  26. package/dist/chunk-JVFP2GAO.js.map +1 -0
  27. package/dist/chunk-KNCZMIZA.js +55 -0
  28. package/dist/chunk-KNCZMIZA.js.map +1 -0
  29. package/dist/chunk-MJO7IJZC.js +44 -0
  30. package/dist/chunk-MJO7IJZC.js.map +1 -0
  31. package/dist/chunk-MPWYZXW7.js +66 -0
  32. package/dist/chunk-MPWYZXW7.js.map +1 -0
  33. package/dist/chunk-OA5ARYJM.js +73 -0
  34. package/dist/chunk-OA5ARYJM.js.map +1 -0
  35. package/dist/chunk-OPHN2B3N.js +147 -0
  36. package/dist/chunk-OPHN2B3N.js.map +1 -0
  37. package/dist/chunk-RTAJJZKO.js +116 -0
  38. package/dist/chunk-RTAJJZKO.js.map +1 -0
  39. package/dist/chunk-SCHZI6YY.js +35 -0
  40. package/dist/chunk-SCHZI6YY.js.map +1 -0
  41. package/dist/chunk-T3IV7SHD.js +388 -0
  42. package/dist/chunk-T3IV7SHD.js.map +1 -0
  43. package/dist/chunk-U65A4HIY.js +133 -0
  44. package/dist/chunk-U65A4HIY.js.map +1 -0
  45. package/dist/core/index.d.ts +20 -0
  46. package/dist/core/index.js +6 -0
  47. package/dist/core/index.js.map +1 -0
  48. package/dist/encoding-B-cb7Duu.d.ts +37 -0
  49. package/dist/errors-C79jA9vX.d.ts +65 -0
  50. package/dist/file-encryption/index.d.ts +135 -0
  51. package/dist/file-encryption/index.js +11 -0
  52. package/dist/file-encryption/index.js.map +1 -0
  53. package/dist/format-versioning/index.d.ts +37 -0
  54. package/dist/format-versioning/index.js +4 -0
  55. package/dist/format-versioning/index.js.map +1 -0
  56. package/dist/index.d.ts +27 -0
  57. package/dist/index.js +24 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/integrity/index.d.ts +46 -0
  60. package/dist/integrity/index.js +6 -0
  61. package/dist/integrity/index.js.map +1 -0
  62. package/dist/kdf/index.d.ts +104 -0
  63. package/dist/kdf/index.js +7 -0
  64. package/dist/kdf/index.js.map +1 -0
  65. package/dist/key-management/index.d.ts +69 -0
  66. package/dist/key-management/index.js +10 -0
  67. package/dist/key-management/index.js.map +1 -0
  68. package/dist/migrations/index.d.ts +41 -0
  69. package/dist/migrations/index.js +4 -0
  70. package/dist/migrations/index.js.map +1 -0
  71. package/dist/post-quantum/index.d.ts +153 -0
  72. package/dist/post-quantum/index.js +3 -0
  73. package/dist/post-quantum/index.js.map +1 -0
  74. package/dist/random/index.d.ts +28 -0
  75. package/dist/random/index.js +5 -0
  76. package/dist/random/index.js.map +1 -0
  77. package/dist/secure-memory/index.d.ts +40 -0
  78. package/dist/secure-memory/index.js +5 -0
  79. package/dist/secure-memory/index.js.map +1 -0
  80. package/dist/signing/index.d.ts +41 -0
  81. package/dist/signing/index.js +5 -0
  82. package/dist/signing/index.js.map +1 -0
  83. package/dist/totp/index.d.ts +69 -0
  84. package/dist/totp/index.js +4 -0
  85. package/dist/totp/index.js.map +1 -0
  86. package/dist/vault-crypto/index.d.ts +225 -0
  87. package/dist/vault-crypto/index.js +465 -0
  88. package/dist/vault-crypto/index.js.map +1 -0
  89. package/dist/vault-encryption/index.d.ts +40 -0
  90. package/dist/vault-encryption/index.js +9 -0
  91. package/dist/vault-encryption/index.js.map +1 -0
  92. package/package.json +137 -0
@@ -0,0 +1,388 @@
1
+ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
2
+
3
+ // src/post-quantum/index.ts
4
+ var SECURITY_STANDARD_VERSION = 1;
5
+ var HYBRID_VERSION = 4;
6
+ var VERSION_RSA_ONLY = 1;
7
+ var VERSION_HYBRID_LEGACY = 2;
8
+ var VERSION_HYBRID_STANDARD_V1 = 3;
9
+ var VERSION_HYBRID_STANDARD_V2 = 4;
10
+ var ML_KEM_768_CIPHERTEXT_SIZE = 1088;
11
+ var RSA_4096_CIPHERTEXT_SIZE = 512;
12
+ var AES_GCM_IV_SIZE = 12;
13
+ var AES_GCM_TAG_SIZE = 16;
14
+ var HYBRID_CIPHERTEXT_MIN_SIZE = 1 + ML_KEM_768_CIPHERTEXT_SIZE + RSA_4096_CIPHERTEXT_SIZE + AES_GCM_IV_SIZE + AES_GCM_TAG_SIZE;
15
+ var HYBRID_KDF_INFO_PREFIX = new TextEncoder().encode("Singra Vault-HybridKDF-v1:");
16
+ var HYBRID_KDF_INFO_V2 = new TextEncoder().encode("Singra Vault-HybridKDF-v2:");
17
+ function buildSharedKeyWrapAad(input) {
18
+ const collectionId = requireNonEmptyAadPart(input.collectionId, "collectionId");
19
+ const senderUserId = requireNonEmptyAadPart(input.senderUserId, "senderUserId");
20
+ const recipientUserId = requireNonEmptyAadPart(input.recipientUserId, "recipientUserId");
21
+ const keyVersion = requireNonEmptyAadPart(String(input.keyVersion), "keyVersion");
22
+ return `sv:shared-key:v1:${collectionId}:${senderUserId}:${recipientUserId}:${keyVersion}`;
23
+ }
24
+ function generatePQKeyPair() {
25
+ const seed = crypto.getRandomValues(new Uint8Array(64));
26
+ const { publicKey, secretKey } = ml_kem768.keygen(seed);
27
+ seed.fill(0);
28
+ return {
29
+ publicKey: uint8ArrayToBase64(publicKey),
30
+ secretKey: uint8ArrayToBase64(secretKey)
31
+ };
32
+ }
33
+ async function generateHybridKeyPair() {
34
+ const pqKeys = generatePQKeyPair();
35
+ const rsaKeyPair = await crypto.subtle.generateKey(
36
+ {
37
+ name: "RSA-OAEP",
38
+ modulusLength: 4096,
39
+ publicExponent: new Uint8Array([1, 0, 1]),
40
+ hash: "SHA-256"
41
+ },
42
+ true,
43
+ ["encrypt", "decrypt"]
44
+ );
45
+ const rsaPublicJwk = await crypto.subtle.exportKey("jwk", rsaKeyPair.publicKey);
46
+ const rsaPrivateJwk = await crypto.subtle.exportKey("jwk", rsaKeyPair.privateKey);
47
+ return {
48
+ pqPublicKey: pqKeys.publicKey,
49
+ pqSecretKey: pqKeys.secretKey,
50
+ rsaPublicKey: JSON.stringify(rsaPublicJwk),
51
+ rsaPrivateKey: JSON.stringify(rsaPrivateJwk)
52
+ };
53
+ }
54
+ async function hybridEncrypt(plaintext, pqPublicKey, rsaPublicKey, aad) {
55
+ const aesKeyBytes = crypto.getRandomValues(new Uint8Array(32));
56
+ const pqPubKeyBytes = base64ToUint8Array(pqPublicKey);
57
+ const { cipherText: pqCiphertext, sharedSecret: pqSharedSecret } = ml_kem768.encapsulate(pqPubKeyBytes);
58
+ const rsaPubKeyJwk = JSON.parse(rsaPublicKey);
59
+ const rsaPubKey = await crypto.subtle.importKey(
60
+ "jwk",
61
+ rsaPubKeyJwk,
62
+ { name: "RSA-OAEP", hash: "SHA-256" },
63
+ false,
64
+ ["encrypt"]
65
+ );
66
+ const rsaCiphertext = await crypto.subtle.encrypt(
67
+ { name: "RSA-OAEP" },
68
+ rsaPubKey,
69
+ asBufferSource(aesKeyBytes)
70
+ );
71
+ const rsaCiphertextBytes = new Uint8Array(rsaCiphertext);
72
+ const combinedKey = await deriveHybridCombinedKeyV2(
73
+ pqSharedSecret,
74
+ aesKeyBytes,
75
+ rsaCiphertextBytes
76
+ );
77
+ const aesKey = await crypto.subtle.importKey(
78
+ "raw",
79
+ asBufferSource(combinedKey),
80
+ { name: "AES-GCM", length: 256 },
81
+ false,
82
+ ["encrypt"]
83
+ );
84
+ const iv = crypto.getRandomValues(new Uint8Array(12));
85
+ const plaintextBytes = new TextEncoder().encode(plaintext);
86
+ const aadBytes = aad ? new TextEncoder().encode(aad) : void 0;
87
+ const gcmParams = { name: "AES-GCM", iv, tagLength: 128 };
88
+ if (aadBytes) {
89
+ gcmParams.additionalData = aadBytes;
90
+ }
91
+ const aesCiphertext = await crypto.subtle.encrypt(
92
+ gcmParams,
93
+ aesKey,
94
+ plaintextBytes
95
+ );
96
+ aesKeyBytes.fill(0);
97
+ pqSharedSecret.fill(0);
98
+ combinedKey.fill(0);
99
+ const aesCiphertextBytes = new Uint8Array(aesCiphertext);
100
+ const totalLength = 1 + pqCiphertext.length + rsaCiphertextBytes.length + iv.length + aesCiphertextBytes.length;
101
+ const combined = new Uint8Array(totalLength);
102
+ let offset = 0;
103
+ combined[offset++] = VERSION_HYBRID_STANDARD_V2;
104
+ combined.set(pqCiphertext, offset);
105
+ offset += pqCiphertext.length;
106
+ combined.set(rsaCiphertextBytes, offset);
107
+ offset += rsaCiphertextBytes.length;
108
+ combined.set(iv, offset);
109
+ offset += iv.length;
110
+ combined.set(aesCiphertextBytes, offset);
111
+ return uint8ArrayToBase64(combined);
112
+ }
113
+ async function hybridDecrypt(ciphertextBase64, pqSecretKey, rsaPrivateKey, aad) {
114
+ return decryptHybridCiphertext(ciphertextBase64, pqSecretKey, rsaPrivateKey, false, aad);
115
+ }
116
+ async function legacyRsaDecrypt(ciphertext, rsaPrivateKey) {
117
+ const rsaPrivKeyJwk = JSON.parse(rsaPrivateKey);
118
+ const rsaPrivKey = await crypto.subtle.importKey(
119
+ "jwk",
120
+ rsaPrivKeyJwk,
121
+ { name: "RSA-OAEP", hash: "SHA-256" },
122
+ false,
123
+ ["decrypt"]
124
+ );
125
+ const plaintextBytes = await crypto.subtle.decrypt(
126
+ { name: "RSA-OAEP" },
127
+ rsaPrivKey,
128
+ asBufferSource(ciphertext)
129
+ );
130
+ return new TextDecoder().decode(plaintextBytes);
131
+ }
132
+ async function hybridWrapKey(sharedKeyJwk, pqPublicKey, rsaPublicKey, aad) {
133
+ return hybridEncrypt(sharedKeyJwk, pqPublicKey, rsaPublicKey, requireAad(aad, "hybridWrapKey"));
134
+ }
135
+ async function hybridUnwrapKey(wrappedKey, pqSecretKey, rsaPrivateKey, aad) {
136
+ return hybridDecrypt(wrappedKey, pqSecretKey, rsaPrivateKey, requireAad(aad, "hybridUnwrapKey"));
137
+ }
138
+ function isHybridEncrypted(ciphertextBase64) {
139
+ try {
140
+ const combined = base64ToUint8Array(ciphertextBase64);
141
+ const v = combined[0];
142
+ return v === VERSION_HYBRID_LEGACY || v === VERSION_HYBRID_STANDARD_V1 || v === VERSION_HYBRID_STANDARD_V2;
143
+ } catch {
144
+ return false;
145
+ }
146
+ }
147
+ function isCurrentStandardEncrypted(ciphertextBase64) {
148
+ try {
149
+ const combined = base64ToUint8Array(ciphertextBase64);
150
+ return combined[0] === VERSION_HYBRID_STANDARD_V2;
151
+ } catch {
152
+ return false;
153
+ }
154
+ }
155
+ async function migrateToHybrid(legacyCiphertext, rsaPrivateKey, pqSecretKey, pqPublicKey, rsaPublicKey, aad) {
156
+ const combined = base64ToUint8Array(legacyCiphertext);
157
+ const version = combined[0];
158
+ if (version === VERSION_HYBRID_STANDARD_V2) {
159
+ if (aad) {
160
+ if (!pqSecretKey) {
161
+ throw new Error("PQ secret key is required to verify current hybrid ciphertext AAD.");
162
+ }
163
+ await decryptHybridCiphertext(
164
+ legacyCiphertext,
165
+ pqSecretKey,
166
+ rsaPrivateKey,
167
+ false,
168
+ aad
169
+ );
170
+ }
171
+ return legacyCiphertext;
172
+ }
173
+ let plaintext;
174
+ if (version === VERSION_HYBRID_STANDARD_V1) {
175
+ if (!pqSecretKey) {
176
+ throw new Error("PQ secret key is required to migrate v0x03 ciphertext.");
177
+ }
178
+ plaintext = await decryptHybridCiphertext(
179
+ legacyCiphertext,
180
+ pqSecretKey,
181
+ rsaPrivateKey,
182
+ true,
183
+ // allowLegacyFormats for internal re-encryption
184
+ aad
185
+ );
186
+ } else if (version === VERSION_RSA_ONLY) {
187
+ plaintext = await legacyRsaDecrypt(combined.slice(1), rsaPrivateKey);
188
+ } else if (version === VERSION_HYBRID_LEGACY) {
189
+ if (!pqSecretKey) {
190
+ throw new Error("PQ secret key is required to migrate legacy hybrid ciphertext.");
191
+ }
192
+ plaintext = await decryptHybridCiphertext(
193
+ legacyCiphertext,
194
+ pqSecretKey,
195
+ rsaPrivateKey,
196
+ true,
197
+ aad
198
+ );
199
+ } else {
200
+ plaintext = await legacyRsaDecrypt(combined, rsaPrivateKey);
201
+ }
202
+ return hybridEncrypt(plaintext, pqPublicKey, rsaPublicKey, aad);
203
+ }
204
+ function uint8ArrayToBase64(bytes) {
205
+ let binary = "";
206
+ for (const byte of bytes) {
207
+ binary += String.fromCharCode(byte);
208
+ }
209
+ return btoa(binary);
210
+ }
211
+ function base64ToUint8Array(base64) {
212
+ const binary = atob(base64);
213
+ const bytes = new Uint8Array(binary.length);
214
+ for (let i = 0; i < binary.length; i++) {
215
+ bytes[i] = binary.charCodeAt(i);
216
+ }
217
+ return bytes;
218
+ }
219
+ function concatUint8Arrays(first, second) {
220
+ const combined = new Uint8Array(first.length + second.length);
221
+ combined.set(first, 0);
222
+ combined.set(second, first.length);
223
+ return combined;
224
+ }
225
+ async function deriveHybridCombinedKey(pqSharedSecret, aesKeyBytes, rsaCiphertext) {
226
+ const baseKey = await crypto.subtle.importKey(
227
+ "raw",
228
+ asBufferSource(pqSharedSecret),
229
+ "HKDF",
230
+ false,
231
+ ["deriveBits"]
232
+ );
233
+ const info = concatUint8Arrays(HYBRID_KDF_INFO_PREFIX, rsaCiphertext);
234
+ try {
235
+ const derivedBits = await crypto.subtle.deriveBits(
236
+ {
237
+ name: "HKDF",
238
+ hash: "SHA-256",
239
+ salt: asBufferSource(aesKeyBytes),
240
+ info: asBufferSource(info)
241
+ },
242
+ baseKey,
243
+ 256
244
+ );
245
+ return new Uint8Array(derivedBits);
246
+ } finally {
247
+ info.fill(0);
248
+ }
249
+ }
250
+ async function deriveHybridCombinedKeyV2(pqSharedSecret, aesKeyBytes, rsaCiphertext) {
251
+ const ikm = concatUint8Arrays(pqSharedSecret, aesKeyBytes);
252
+ const baseKey = await crypto.subtle.importKey(
253
+ "raw",
254
+ asBufferSource(ikm),
255
+ "HKDF",
256
+ false,
257
+ ["deriveBits"]
258
+ );
259
+ const info = concatUint8Arrays(HYBRID_KDF_INFO_V2, rsaCiphertext);
260
+ try {
261
+ const derivedBits = await crypto.subtle.deriveBits(
262
+ {
263
+ name: "HKDF",
264
+ hash: "SHA-256",
265
+ salt: asBufferSource(new Uint8Array(32)),
266
+ // zero-byte salt (NIST-recommended)
267
+ info: asBufferSource(info)
268
+ },
269
+ baseKey,
270
+ 256
271
+ );
272
+ return new Uint8Array(derivedBits);
273
+ } finally {
274
+ ikm.fill(0);
275
+ info.fill(0);
276
+ }
277
+ }
278
+ async function decryptHybridCiphertext(ciphertextBase64, pqSecretKey, rsaPrivateKey, allowLegacyFormats, aad) {
279
+ const combined = base64ToUint8Array(ciphertextBase64);
280
+ const version = combined[0];
281
+ if (!allowLegacyFormats && version !== VERSION_HYBRID_STANDARD_V1 && version !== VERSION_HYBRID_STANDARD_V2) {
282
+ throw new Error("Security Standard v1 requires hybrid ciphertext version 3 or 4.");
283
+ }
284
+ if (version === VERSION_RSA_ONLY) {
285
+ if (!allowLegacyFormats) {
286
+ throw new Error("RSA-only ciphertext is blocked by Security Standard v1.");
287
+ }
288
+ return legacyRsaDecrypt(combined.slice(1), rsaPrivateKey);
289
+ }
290
+ if (version !== VERSION_HYBRID_STANDARD_V2 && version !== VERSION_HYBRID_STANDARD_V1 && version !== VERSION_HYBRID_LEGACY) {
291
+ throw new Error(`Unsupported encryption version: ${version}`);
292
+ }
293
+ const { pqCiphertext, rsaCiphertext, iv, aesCiphertext } = parseHybridCiphertext(combined);
294
+ const pqSecretKeyBytes = base64ToUint8Array(pqSecretKey);
295
+ const pqSharedSecret = ml_kem768.decapsulate(pqCiphertext, pqSecretKeyBytes);
296
+ const rsaPrivKeyJwk = JSON.parse(rsaPrivateKey);
297
+ const rsaPrivKey = await crypto.subtle.importKey(
298
+ "jwk",
299
+ rsaPrivKeyJwk,
300
+ { name: "RSA-OAEP", hash: "SHA-256" },
301
+ false,
302
+ ["decrypt"]
303
+ );
304
+ const aesKeyBytes = new Uint8Array(await crypto.subtle.decrypt(
305
+ { name: "RSA-OAEP" },
306
+ rsaPrivKey,
307
+ asBufferSource(rsaCiphertext)
308
+ ));
309
+ let combinedKey;
310
+ if (version === VERSION_HYBRID_STANDARD_V2) {
311
+ combinedKey = await deriveHybridCombinedKeyV2(
312
+ pqSharedSecret,
313
+ aesKeyBytes,
314
+ rsaCiphertext
315
+ );
316
+ } else {
317
+ combinedKey = await deriveHybridCombinedKey(
318
+ pqSharedSecret,
319
+ aesKeyBytes,
320
+ rsaCiphertext
321
+ );
322
+ }
323
+ const aesKey = await crypto.subtle.importKey(
324
+ "raw",
325
+ asBufferSource(combinedKey),
326
+ { name: "AES-GCM", length: 256 },
327
+ false,
328
+ ["decrypt"]
329
+ );
330
+ try {
331
+ const aadBytes = aad ? new TextEncoder().encode(aad) : void 0;
332
+ const gcmParams = { name: "AES-GCM", iv: asBufferSource(iv), tagLength: 128 };
333
+ if (aadBytes) {
334
+ gcmParams.additionalData = aadBytes;
335
+ }
336
+ const plaintextBytes = await crypto.subtle.decrypt(
337
+ gcmParams,
338
+ aesKey,
339
+ asBufferSource(aesCiphertext)
340
+ );
341
+ return new TextDecoder().decode(plaintextBytes);
342
+ } finally {
343
+ aesKeyBytes.fill(0);
344
+ pqSharedSecret.fill(0);
345
+ combinedKey.fill(0);
346
+ }
347
+ }
348
+ function parseHybridCiphertext(combined) {
349
+ const version = combined[0];
350
+ if (combined.length < HYBRID_CIPHERTEXT_MIN_SIZE || version !== VERSION_HYBRID_LEGACY && version !== VERSION_HYBRID_STANDARD_V1 && version !== VERSION_HYBRID_STANDARD_V2) {
351
+ throw new Error("Invalid hybrid ciphertext format.");
352
+ }
353
+ let offset = 1;
354
+ const pqCiphertext = combined.slice(offset, offset + ML_KEM_768_CIPHERTEXT_SIZE);
355
+ offset += ML_KEM_768_CIPHERTEXT_SIZE;
356
+ const rsaCiphertext = combined.slice(offset, offset + RSA_4096_CIPHERTEXT_SIZE);
357
+ offset += RSA_4096_CIPHERTEXT_SIZE;
358
+ const iv = combined.slice(offset, offset + AES_GCM_IV_SIZE);
359
+ offset += AES_GCM_IV_SIZE;
360
+ const aesCiphertext = combined.slice(offset);
361
+ if (pqCiphertext.length !== ML_KEM_768_CIPHERTEXT_SIZE || rsaCiphertext.length !== RSA_4096_CIPHERTEXT_SIZE || iv.length !== AES_GCM_IV_SIZE || aesCiphertext.length < AES_GCM_TAG_SIZE) {
362
+ throw new Error("Invalid hybrid ciphertext format.");
363
+ }
364
+ return { pqCiphertext, rsaCiphertext, iv, aesCiphertext };
365
+ }
366
+ function requireAad(aad, operation) {
367
+ if (typeof aad !== "string" || aad.trim().length === 0) {
368
+ throw new Error(`${operation} requires non-empty AAD for wrapped-key context binding.`);
369
+ }
370
+ return aad;
371
+ }
372
+ function requireNonEmptyAadPart(value, label) {
373
+ const normalized = value.trim();
374
+ if (!normalized) {
375
+ throw new Error(`Missing AAD component: ${label}`);
376
+ }
377
+ if (normalized.includes(":")) {
378
+ throw new Error(`AAD component must not contain ':': ${label}`);
379
+ }
380
+ return normalized;
381
+ }
382
+ function asBufferSource(bytes) {
383
+ return bytes;
384
+ }
385
+
386
+ export { HYBRID_VERSION, SECURITY_STANDARD_VERSION, buildSharedKeyWrapAad, generateHybridKeyPair, generatePQKeyPair, hybridDecrypt, hybridEncrypt, hybridUnwrapKey, hybridWrapKey, isCurrentStandardEncrypted, isHybridEncrypted, migrateToHybrid };
387
+ //# sourceMappingURL=chunk-T3IV7SHD.js.map
388
+ //# sourceMappingURL=chunk-T3IV7SHD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/post-quantum/index.ts"],"names":[],"mappings":"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","file":"chunk-T3IV7SHD.js","sourcesContent":["/**\r\n * DIS — Defensive Integration Shield · post-quantum hybrid key wrapping.\r\n * Powered by DIS — Defensive Integration Shield.\r\n *\r\n * Hybrid key wrapping combining:\r\n * - ML-KEM-768 (FIPS 203) for post-quantum key encapsulation\r\n * - RSA-4096-OAEP for classical encryption\r\n *\r\n * In the product threat model this protects sharing and emergency-access\r\n * keys against \"harvest now, decrypt later\" attacks. It is NOT the encryption\r\n * layer for vault item payloads, which remain AES-256-GCM encrypted with\r\n * user-derived symmetric keys (see `@dis/shield/vault-encryption`).\r\n *\r\n * Wire format is preserved byte-for-byte from the legacy Singra implementation:\r\n * version(1) || pq_ct(1088) || rsa_ct(512) || iv(12) || aes_ct(variable)\r\n * with version bytes 0x01 (RSA-only), 0x02 (legacy hybrid), 0x03 (HKDF-v1),\r\n * 0x04 (HKDF-v2, current). Changing any constant below breaks decryption of\r\n * already-stored sharing/emergency keys — treat as a hard compatibility gate.\r\n *\r\n * @see https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf\r\n */\r\n\r\nimport { ml_kem768 } from '@noble/post-quantum/ml-kem.js';\r\n\r\n// ============ Constants ============\r\n\r\n/**\r\n * Product-wide security standard version. Centralized so all hybrid/PQ\r\n * sharing-key provisioning and runtime enforcement paths stay in sync.\r\n */\r\nexport const SECURITY_STANDARD_VERSION = 1;\r\n\r\n/** Current hybrid ciphertext version (v2 HKDF construction) */\r\nexport const HYBRID_VERSION = 4;\r\n\r\n/** Version byte for legacy RSA-only encryption */\r\nconst VERSION_RSA_ONLY = 0x01;\r\n\r\n/** Version byte for legacy hybrid ML-KEM + RSA encryption */\r\nconst VERSION_HYBRID_LEGACY = 0x02;\r\n\r\n/** Version byte for Security Standard v1 hybrid (HKDF-v1, legacy) */\r\nconst VERSION_HYBRID_STANDARD_V1 = 0x03;\r\n\r\n/** Version byte for Security Standard v1 hybrid (HKDF-v2, current) */\r\nconst VERSION_HYBRID_STANDARD_V2 = 0x04;\r\n\r\n/** ML-KEM-768 ciphertext size in bytes */\r\nconst ML_KEM_768_CIPHERTEXT_SIZE = 1088;\r\nconst RSA_4096_CIPHERTEXT_SIZE = 512;\r\nconst AES_GCM_IV_SIZE = 12;\r\nconst AES_GCM_TAG_SIZE = 16;\r\nconst HYBRID_CIPHERTEXT_MIN_SIZE =\r\n 1 + ML_KEM_768_CIPHERTEXT_SIZE + RSA_4096_CIPHERTEXT_SIZE + AES_GCM_IV_SIZE + AES_GCM_TAG_SIZE;\r\n\r\n/** ML-KEM-768 public key size in bytes */\r\nconst ML_KEM_768_PUBLIC_KEY_SIZE = 1184;\r\n\r\n/** ML-KEM-768 secret key size in bytes */\r\nconst ML_KEM_768_SECRET_KEY_SIZE = 2400;\r\n\r\n/** ML-KEM-768 shared secret size in bytes */\r\nconst ML_KEM_768_SHARED_SECRET_SIZE = 32;\r\n\r\n/** HKDF info prefix for legacy hybrid key combination (v1) */\r\nconst HYBRID_KDF_INFO_PREFIX = new TextEncoder().encode('Singra Vault-HybridKDF-v1:');\r\n\r\n/** HKDF info string for standard-compliant hybrid key combination (v2) */\r\nconst HYBRID_KDF_INFO_V2 = new TextEncoder().encode('Singra Vault-HybridKDF-v2:');\r\n\r\nexport interface SharedKeyWrapAadInput {\r\n collectionId: string;\r\n senderUserId: string;\r\n recipientUserId: string;\r\n keyVersion: string | number;\r\n}\r\n\r\nexport function buildSharedKeyWrapAad(input: SharedKeyWrapAadInput): string {\r\n const collectionId = requireNonEmptyAadPart(input.collectionId, 'collectionId');\r\n const senderUserId = requireNonEmptyAadPart(input.senderUserId, 'senderUserId');\r\n const recipientUserId = requireNonEmptyAadPart(input.recipientUserId, 'recipientUserId');\r\n const keyVersion = requireNonEmptyAadPart(String(input.keyVersion), 'keyVersion');\r\n return `sv:shared-key:v1:${collectionId}:${senderUserId}:${recipientUserId}:${keyVersion}`;\r\n}\r\n\r\n// ============ Key Generation ============\r\n\r\n/**\r\n * Generates a new ML-KEM-768 key pair.\r\n * \r\n * @returns Object with base64-encoded public and secret keys\r\n */\r\nexport function generatePQKeyPair(): PQKeyPair {\r\n const seed = crypto.getRandomValues(new Uint8Array(64));\r\n const { publicKey, secretKey } = ml_kem768.keygen(seed);\r\n \r\n // Zero the seed immediately\r\n seed.fill(0);\r\n \r\n return {\r\n publicKey: uint8ArrayToBase64(publicKey),\r\n secretKey: uint8ArrayToBase64(secretKey),\r\n };\r\n}\r\n\r\n/**\r\n * Generates a hybrid key pair combining ML-KEM-768 and RSA-4096.\r\n * \r\n * @returns Object with both PQ and RSA keys\r\n */\r\nexport async function generateHybridKeyPair(): Promise<HybridKeyPair> {\r\n // Generate ML-KEM-768 key pair\r\n const pqKeys = generatePQKeyPair();\r\n \r\n // Generate RSA-4096 key pair\r\n const rsaKeyPair = await crypto.subtle.generateKey(\r\n {\r\n name: 'RSA-OAEP',\r\n modulusLength: 4096,\r\n publicExponent: new Uint8Array([1, 0, 1]),\r\n hash: 'SHA-256',\r\n },\r\n true,\r\n ['encrypt', 'decrypt']\r\n );\r\n \r\n const rsaPublicJwk = await crypto.subtle.exportKey('jwk', rsaKeyPair.publicKey);\r\n const rsaPrivateJwk = await crypto.subtle.exportKey('jwk', rsaKeyPair.privateKey);\r\n \r\n return {\r\n pqPublicKey: pqKeys.publicKey,\r\n pqSecretKey: pqKeys.secretKey,\r\n rsaPublicKey: JSON.stringify(rsaPublicJwk),\r\n rsaPrivateKey: JSON.stringify(rsaPrivateJwk),\r\n };\r\n}\r\n\r\n// ============ Hybrid Key Wrapping ============\r\n\r\n/**\r\n * Encrypts key material using hybrid ML-KEM-768 + RSA-4096-OAEP encryption.\r\n * \r\n * The supplied key material is encrypted with a randomly generated AES-256 key.\r\n * This AES key is then encapsulated/encrypted with both:\r\n * 1. ML-KEM-768 (post-quantum KEM)\r\n * 2. RSA-4096-OAEP (classically secure)\r\n * \r\n * Format: version(1) || pq_ciphertext(1088) || rsa_ciphertext(512) || iv(12) || aes_ciphertext(variable)\r\n * \r\n * @param plaintext - Serialized key material to wrap\r\n * @param pqPublicKey - Base64-encoded ML-KEM-768 public key\r\n * @param rsaPublicKey - JWK string of RSA-4096 public key\r\n * @param aad - Optional additional authenticated data for AES-GCM context binding\r\n * @returns Base64-encoded hybrid ciphertext\r\n */\r\nexport async function hybridEncrypt(\r\n plaintext: string,\r\n pqPublicKey: string,\r\n rsaPublicKey: string,\r\n aad?: string\r\n): Promise<string> {\r\n // 1. Generate random AES-256 key (32 bytes)\r\n const aesKeyBytes = crypto.getRandomValues(new Uint8Array(32));\r\n \r\n // 2. Encapsulate with ML-KEM-768\r\n const pqPubKeyBytes = base64ToUint8Array(pqPublicKey);\r\n const { cipherText: pqCiphertext, sharedSecret: pqSharedSecret } = \r\n ml_kem768.encapsulate(pqPubKeyBytes);\r\n \r\n // 3. Encrypt AES key with RSA-OAEP\r\n const rsaPubKeyJwk = JSON.parse(rsaPublicKey);\r\n const rsaPubKey = await crypto.subtle.importKey(\r\n 'jwk',\r\n rsaPubKeyJwk,\r\n { name: 'RSA-OAEP', hash: 'SHA-256' },\r\n false,\r\n ['encrypt']\r\n );\r\n \r\n const rsaCiphertext = await crypto.subtle.encrypt(\r\n { name: 'RSA-OAEP' },\r\n rsaPubKey,\r\n asBufferSource(aesKeyBytes)\r\n );\r\n\r\n const rsaCiphertextBytes = new Uint8Array(rsaCiphertext);\r\n\r\n // 4. Derive combined key using standard-compliant HKDF-v2\r\n const combinedKey = await deriveHybridCombinedKeyV2(\r\n pqSharedSecret,\r\n aesKeyBytes,\r\n rsaCiphertextBytes,\r\n );\r\n \r\n // 5. Encrypt plaintext with combined AES key\r\n const aesKey = await crypto.subtle.importKey(\r\n 'raw',\r\n asBufferSource(combinedKey),\r\n { name: 'AES-GCM', length: 256 },\r\n false,\r\n ['encrypt']\r\n );\r\n \r\n const iv = crypto.getRandomValues(new Uint8Array(12));\r\n const plaintextBytes = new TextEncoder().encode(plaintext);\r\n const aadBytes = aad ? new TextEncoder().encode(aad) : undefined;\r\n const gcmParams: AesGcmParams = { name: 'AES-GCM', iv, tagLength: 128 };\r\n if (aadBytes) {\r\n gcmParams.additionalData = aadBytes;\r\n }\r\n const aesCiphertext = await crypto.subtle.encrypt(\r\n gcmParams,\r\n aesKey,\r\n plaintextBytes\r\n );\r\n \r\n // 6. Zero sensitive data\r\n aesKeyBytes.fill(0);\r\n pqSharedSecret.fill(0);\r\n combinedKey.fill(0);\r\n \r\n // 7. Combine: version || pq_ciphertext || rsa_ciphertext || iv || aes_ciphertext\r\n const aesCiphertextBytes = new Uint8Array(aesCiphertext);\r\n \r\n const totalLength = 1 + pqCiphertext.length + rsaCiphertextBytes.length + \r\n iv.length + aesCiphertextBytes.length;\r\n const combined = new Uint8Array(totalLength);\r\n \r\n let offset = 0;\r\n combined[offset++] = VERSION_HYBRID_STANDARD_V2;\r\n combined.set(pqCiphertext, offset);\r\n offset += pqCiphertext.length;\r\n combined.set(rsaCiphertextBytes, offset);\r\n offset += rsaCiphertextBytes.length;\r\n combined.set(iv, offset);\r\n offset += iv.length;\r\n combined.set(aesCiphertextBytes, offset);\r\n \r\n return uint8ArrayToBase64(combined);\r\n}\r\n\r\n/**\r\n * Decrypts hybrid ML-KEM-768 + RSA-4096-OAEP wrapped key material.\r\n * \r\n * @param ciphertextBase64 - Base64-encoded hybrid ciphertext\r\n * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key\r\n * @param rsaPrivateKey - JWK string of RSA-4096 private key\r\n * @param aad - Optional additional authenticated data (must match encrypt-time AAD)\r\n * @returns Decrypted plaintext\r\n * @throws Error if decryption fails or version is unsupported\r\n */\r\nexport async function hybridDecrypt(\r\n ciphertextBase64: string,\r\n pqSecretKey: string,\r\n rsaPrivateKey: string,\r\n aad?: string\r\n): Promise<string> {\r\n return decryptHybridCiphertext(ciphertextBase64, pqSecretKey, rsaPrivateKey, false, aad);\r\n}\r\n\r\n/**\r\n * Legacy RSA-only decryption for backward compatibility.\r\n * Used when decrypting key material wrapped before the PQ upgrade.\r\n */\r\nasync function legacyRsaDecrypt(\r\n ciphertext: Uint8Array,\r\n rsaPrivateKey: string\r\n): Promise<string> {\r\n const rsaPrivKeyJwk = JSON.parse(rsaPrivateKey);\r\n const rsaPrivKey = await crypto.subtle.importKey(\r\n 'jwk',\r\n rsaPrivKeyJwk,\r\n { name: 'RSA-OAEP', hash: 'SHA-256' },\r\n false,\r\n ['decrypt']\r\n );\r\n \r\n const plaintextBytes = await crypto.subtle.decrypt(\r\n { name: 'RSA-OAEP' },\r\n rsaPrivKey,\r\n asBufferSource(ciphertext)\r\n );\r\n \r\n return new TextDecoder().decode(plaintextBytes);\r\n}\r\n\r\n// ============ Key Wrapping for Shared Collections ============\r\n\r\n/**\r\n * Wraps a shared AES key using hybrid encryption.\r\n * Used for shared collections where each member gets a wrapped copy.\r\n * \r\n * @param sharedKeyJwk - JWK string of the shared AES-256 key\r\n * @param pqPublicKey - Base64-encoded ML-KEM-768 public key\r\n * @param rsaPublicKey - JWK string of RSA-4096 public key\r\n * @param aad - Optional additional authenticated data (e.g. collection ID)\r\n * @returns Base64-encoded wrapped key\r\n */\r\nexport async function hybridWrapKey(\r\n sharedKeyJwk: string,\r\n pqPublicKey: string,\r\n rsaPublicKey: string,\r\n aad: string\r\n): Promise<string> {\r\n return hybridEncrypt(sharedKeyJwk, pqPublicKey, rsaPublicKey, requireAad(aad, 'hybridWrapKey'));\r\n}\r\n\r\n/**\r\n * Unwraps a shared AES key using hybrid decryption.\r\n * \r\n * @param wrappedKey - Base64-encoded wrapped key\r\n * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key\r\n * @param rsaPrivateKey - JWK string of RSA-4096 private key\r\n * @param aad - Optional additional authenticated data (must match wrap-time AAD)\r\n * @returns JWK string of the shared AES-256 key\r\n */\r\nexport async function hybridUnwrapKey(\r\n wrappedKey: string,\r\n pqSecretKey: string,\r\n rsaPrivateKey: string,\r\n aad: string\r\n): Promise<string> {\r\n return hybridDecrypt(wrappedKey, pqSecretKey, rsaPrivateKey, requireAad(aad, 'hybridUnwrapKey'));\r\n}\r\n\r\n// ============ Migration Helpers ============\r\n\r\n/**\r\n * Checks if wrapped key material uses any hybrid (post-quantum) encryption version.\r\n * Recognizes legacy hybrid (0x02), standard v1 (0x03), and standard v2 (0x04).\r\n * \r\n * @param ciphertextBase64 - Base64-encoded ciphertext\r\n * @returns true if any hybrid wrapped-key version, false if legacy RSA-only or unknown\r\n */\r\nexport function isHybridEncrypted(ciphertextBase64: string): boolean {\r\n try {\r\n const combined = base64ToUint8Array(ciphertextBase64);\r\n const v = combined[0];\r\n return v === VERSION_HYBRID_LEGACY ||\r\n v === VERSION_HYBRID_STANDARD_V1 ||\r\n v === VERSION_HYBRID_STANDARD_V2;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if a ciphertext uses the current standard encryption (v2 HKDF, version 0x04).\r\n * Use this for security enforcement checks where only the latest format is acceptable.\r\n * \r\n * @param ciphertextBase64 - Base64-encoded ciphertext\r\n * @returns true if current standard (0x04), false otherwise\r\n */\r\nexport function isCurrentStandardEncrypted(ciphertextBase64: string): boolean {\r\n try {\r\n const combined = base64ToUint8Array(ciphertextBase64);\r\n return combined[0] === VERSION_HYBRID_STANDARD_V2;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Re-wraps legacy RSA-only or older hybrid key material with current hybrid key wrapping (v2).\r\n * Used during migration to post-quantum protection for sharing and emergency keys.\r\n * \r\n * - Version 0x04: already current, returned unchanged.\r\n * - Version 0x03: decrypted with legacy HKDF-v1, re-encrypted with HKDF-v2.\r\n * - Version 0x02: decrypted with legacy hybrid path, re-encrypted.\r\n * - Version 0x01 / unknown: decrypted with RSA-only, re-encrypted.\r\n * \r\n * @param legacyCiphertext - Base64-encoded legacy ciphertext\r\n * @param rsaPrivateKey - JWK string of RSA private key for decryption\r\n * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key (required for hybrid legacy)\r\n * @param pqPublicKey - Base64-encoded ML-KEM-768 public key\r\n * @param rsaPublicKey - JWK string of RSA public key\r\n * @returns Base64-encoded hybrid ciphertext (version 0x04)\r\n */\r\nexport async function migrateToHybrid(\r\n legacyCiphertext: string,\r\n rsaPrivateKey: string,\r\n pqSecretKey: string | null,\r\n pqPublicKey: string,\r\n rsaPublicKey: string,\r\n aad?: string,\r\n): Promise<string> {\r\n const combined = base64ToUint8Array(legacyCiphertext);\r\n const version = combined[0];\r\n\r\n // Already current standard — no migration needed\r\n if (version === VERSION_HYBRID_STANDARD_V2) {\r\n if (aad) {\r\n if (!pqSecretKey) {\r\n throw new Error('PQ secret key is required to verify current hybrid ciphertext AAD.');\r\n }\r\n await decryptHybridCiphertext(\r\n legacyCiphertext,\r\n pqSecretKey,\r\n rsaPrivateKey,\r\n false,\r\n aad,\r\n );\r\n }\r\n return legacyCiphertext;\r\n }\r\n\r\n let plaintext: string;\r\n\r\n if (version === VERSION_HYBRID_STANDARD_V1) {\r\n // v0x03 → decrypt with legacy HKDF-v1, re-encrypt with HKDF-v2\r\n if (!pqSecretKey) {\r\n throw new Error('PQ secret key is required to migrate v0x03 ciphertext.');\r\n }\r\n plaintext = await decryptHybridCiphertext(\r\n legacyCiphertext,\r\n pqSecretKey,\r\n rsaPrivateKey,\r\n true, // allowLegacyFormats for internal re-encryption\r\n aad,\r\n );\r\n } else if (version === VERSION_RSA_ONLY) {\r\n plaintext = await legacyRsaDecrypt(combined.slice(1), rsaPrivateKey);\r\n } else if (version === VERSION_HYBRID_LEGACY) {\r\n if (!pqSecretKey) {\r\n throw new Error('PQ secret key is required to migrate legacy hybrid ciphertext.');\r\n }\r\n\r\n plaintext = await decryptHybridCiphertext(\r\n legacyCiphertext,\r\n pqSecretKey,\r\n rsaPrivateKey,\r\n true,\r\n aad,\r\n );\r\n } else {\r\n // Very old format without version byte - assume raw RSA ciphertext\r\n plaintext = await legacyRsaDecrypt(combined, rsaPrivateKey);\r\n }\r\n\r\n return hybridEncrypt(plaintext, pqPublicKey, rsaPublicKey, aad);\r\n}\r\n\r\n// ============ Utility Functions ============\r\n\r\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\r\n let binary = '';\r\n for (const byte of bytes) {\r\n binary += String.fromCharCode(byte);\r\n }\r\n return btoa(binary);\r\n}\r\n\r\nfunction base64ToUint8Array(base64: string): Uint8Array {\r\n const binary = atob(base64);\r\n const bytes = new Uint8Array(binary.length);\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i);\r\n }\r\n return bytes;\r\n}\r\n\r\nfunction concatUint8Arrays(first: Uint8Array, second: Uint8Array): Uint8Array {\r\n const combined = new Uint8Array(first.length + second.length);\r\n combined.set(first, 0);\r\n combined.set(second, first.length);\r\n return combined;\r\n}\r\n\r\n/**\r\n * Legacy HKDF key derivation for version 0x03 ciphertexts.\r\n * Uses pqSharedSecret as IKM and aesKeyBytes as salt (non-standard).\r\n * Kept only for backward-compatible decryption of existing 0x03 data.\r\n *\r\n * @private\r\n */\r\nasync function deriveHybridCombinedKey(\r\n pqSharedSecret: Uint8Array,\r\n aesKeyBytes: Uint8Array,\r\n rsaCiphertext: Uint8Array,\r\n): Promise<Uint8Array> {\r\n const baseKey = await crypto.subtle.importKey(\r\n 'raw',\r\n asBufferSource(pqSharedSecret),\r\n 'HKDF',\r\n false,\r\n ['deriveBits'],\r\n );\r\n\r\n const info = concatUint8Arrays(HYBRID_KDF_INFO_PREFIX, rsaCiphertext);\r\n try {\r\n const derivedBits = await crypto.subtle.deriveBits(\r\n {\r\n name: 'HKDF',\r\n hash: 'SHA-256',\r\n salt: asBufferSource(aesKeyBytes),\r\n info: asBufferSource(info),\r\n },\r\n baseKey,\r\n 256,\r\n );\r\n\r\n return new Uint8Array(derivedBits);\r\n } finally {\r\n info.fill(0);\r\n }\r\n}\r\n\r\n/**\r\n * Standard-compliant HKDF key derivation for version 0x04 ciphertexts.\r\n * Both secrets (pqSharedSecret and aesKeyBytes) are concatenated as IKM.\r\n * Salt is zero-bytes (NIST-recommended for hybrid KDF).\r\n * Info includes RSA ciphertext for context binding.\r\n *\r\n * @private\r\n */\r\nasync function deriveHybridCombinedKeyV2(\r\n pqSharedSecret: Uint8Array,\r\n aesKeyBytes: Uint8Array,\r\n rsaCiphertext: Uint8Array,\r\n): Promise<Uint8Array> {\r\n // IKM = pqSharedSecret || aesKeyBytes (both secrets as input keying material)\r\n const ikm = concatUint8Arrays(pqSharedSecret, aesKeyBytes);\r\n\r\n const baseKey = await crypto.subtle.importKey(\r\n 'raw',\r\n asBufferSource(ikm),\r\n 'HKDF',\r\n false,\r\n ['deriveBits'],\r\n );\r\n\r\n const info = concatUint8Arrays(HYBRID_KDF_INFO_V2, rsaCiphertext);\r\n try {\r\n const derivedBits = await crypto.subtle.deriveBits(\r\n {\r\n name: 'HKDF',\r\n hash: 'SHA-256',\r\n salt: asBufferSource(new Uint8Array(32)), // zero-byte salt (NIST-recommended)\r\n info: asBufferSource(info),\r\n },\r\n baseKey,\r\n 256,\r\n );\r\n\r\n return new Uint8Array(derivedBits);\r\n } finally {\r\n ikm.fill(0);\r\n info.fill(0);\r\n }\r\n}\r\n\r\n/**\r\n * Internal decrypt function supporting all hybrid ciphertext versions.\r\n *\r\n * - Version 0x04: Uses HKDF-v2 (standard-compliant).\r\n * - Version 0x03: Uses HKDF-v1 (legacy, kept for backward compat).\r\n * - Version 0x02: Legacy hybrid (same decrypt path as 0x03).\r\n * - Version 0x01: RSA-only (only if allowLegacyFormats=true).\r\n *\r\n * @param allowLegacyFormats - If false, blocks versions 0x01 and 0x02.\r\n * Versions 0x03 and 0x04 are always accepted.\r\n * @param aad - Optional AAD for AES-GCM context binding.\r\n */\r\nasync function decryptHybridCiphertext(\r\n ciphertextBase64: string,\r\n pqSecretKey: string,\r\n rsaPrivateKey: string,\r\n allowLegacyFormats: boolean,\r\n aad?: string,\r\n): Promise<string> {\r\n const combined = base64ToUint8Array(ciphertextBase64);\r\n const version = combined[0];\r\n\r\n // Versions 0x03 and 0x04 are always accepted.\r\n // Versions 0x01 and 0x02 are only accepted if allowLegacyFormats is true.\r\n if (!allowLegacyFormats &&\r\n version !== VERSION_HYBRID_STANDARD_V1 &&\r\n version !== VERSION_HYBRID_STANDARD_V2) {\r\n throw new Error('Security Standard v1 requires hybrid ciphertext version 3 or 4.');\r\n }\r\n\r\n if (version === VERSION_RSA_ONLY) {\r\n if (!allowLegacyFormats) {\r\n throw new Error('RSA-only ciphertext is blocked by Security Standard v1.');\r\n }\r\n\r\n return legacyRsaDecrypt(combined.slice(1), rsaPrivateKey);\r\n }\r\n\r\n if (version !== VERSION_HYBRID_STANDARD_V2 &&\r\n version !== VERSION_HYBRID_STANDARD_V1 &&\r\n version !== VERSION_HYBRID_LEGACY) {\r\n throw new Error(`Unsupported encryption version: ${version}`);\r\n }\r\n\r\n const { pqCiphertext, rsaCiphertext, iv, aesCiphertext } = parseHybridCiphertext(combined);\r\n\r\n // Decapsulate ML-KEM-768 shared secret.\r\n const pqSecretKeyBytes = base64ToUint8Array(pqSecretKey);\r\n const pqSharedSecret = ml_kem768.decapsulate(pqCiphertext, pqSecretKeyBytes);\r\n\r\n // Decrypt AES key with RSA-OAEP.\r\n const rsaPrivKeyJwk = JSON.parse(rsaPrivateKey);\r\n const rsaPrivKey = await crypto.subtle.importKey(\r\n 'jwk',\r\n rsaPrivKeyJwk,\r\n { name: 'RSA-OAEP', hash: 'SHA-256' },\r\n false,\r\n ['decrypt']\r\n );\r\n\r\n const aesKeyBytes = new Uint8Array(await crypto.subtle.decrypt(\r\n { name: 'RSA-OAEP' },\r\n rsaPrivKey,\r\n asBufferSource(rsaCiphertext)\r\n ));\r\n\r\n // Select KDF based on version\r\n let combinedKey: Uint8Array;\r\n if (version === VERSION_HYBRID_STANDARD_V2) {\r\n combinedKey = await deriveHybridCombinedKeyV2(\r\n pqSharedSecret,\r\n aesKeyBytes,\r\n rsaCiphertext,\r\n );\r\n } else {\r\n // 0x03 and 0x02 use legacy HKDF-v1\r\n combinedKey = await deriveHybridCombinedKey(\r\n pqSharedSecret,\r\n aesKeyBytes,\r\n rsaCiphertext,\r\n );\r\n }\r\n\r\n // Decrypt plaintext with combined AES key.\r\n const aesKey = await crypto.subtle.importKey(\r\n 'raw',\r\n asBufferSource(combinedKey),\r\n { name: 'AES-GCM', length: 256 },\r\n false,\r\n ['decrypt']\r\n );\r\n\r\n try {\r\n const aadBytes = aad ? new TextEncoder().encode(aad) : undefined;\r\n const gcmParams: AesGcmParams = { name: 'AES-GCM', iv: asBufferSource(iv), tagLength: 128 };\r\n if (aadBytes) {\r\n gcmParams.additionalData = aadBytes;\r\n }\r\n const plaintextBytes = await crypto.subtle.decrypt(\r\n gcmParams,\r\n aesKey,\r\n asBufferSource(aesCiphertext)\r\n );\r\n\r\n return new TextDecoder().decode(plaintextBytes);\r\n } finally {\r\n aesKeyBytes.fill(0);\r\n pqSharedSecret.fill(0);\r\n combinedKey.fill(0);\r\n }\r\n}\r\n\r\nfunction parseHybridCiphertext(combined: Uint8Array): ParsedHybridCiphertext {\r\n const version = combined[0];\r\n if (\r\n combined.length < HYBRID_CIPHERTEXT_MIN_SIZE ||\r\n (\r\n version !== VERSION_HYBRID_LEGACY &&\r\n version !== VERSION_HYBRID_STANDARD_V1 &&\r\n version !== VERSION_HYBRID_STANDARD_V2\r\n )\r\n ) {\r\n throw new Error('Invalid hybrid ciphertext format.');\r\n }\r\n\r\n let offset = 1;\r\n\r\n const pqCiphertext = combined.slice(offset, offset + ML_KEM_768_CIPHERTEXT_SIZE);\r\n offset += ML_KEM_768_CIPHERTEXT_SIZE;\r\n\r\n const rsaCiphertext = combined.slice(offset, offset + RSA_4096_CIPHERTEXT_SIZE);\r\n offset += RSA_4096_CIPHERTEXT_SIZE;\r\n\r\n const iv = combined.slice(offset, offset + AES_GCM_IV_SIZE);\r\n offset += AES_GCM_IV_SIZE;\r\n\r\n const aesCiphertext = combined.slice(offset);\r\n if (\r\n pqCiphertext.length !== ML_KEM_768_CIPHERTEXT_SIZE ||\r\n rsaCiphertext.length !== RSA_4096_CIPHERTEXT_SIZE ||\r\n iv.length !== AES_GCM_IV_SIZE ||\r\n aesCiphertext.length < AES_GCM_TAG_SIZE\r\n ) {\r\n throw new Error('Invalid hybrid ciphertext format.');\r\n }\r\n\r\n return { pqCiphertext, rsaCiphertext, iv, aesCiphertext };\r\n}\r\n\r\nfunction requireAad(aad: string, operation: string): string {\r\n if (typeof aad !== 'string' || aad.trim().length === 0) {\r\n throw new Error(`${operation} requires non-empty AAD for wrapped-key context binding.`);\r\n }\r\n return aad;\r\n}\r\n\r\nfunction requireNonEmptyAadPart(value: string, label: string): string {\r\n const normalized = value.trim();\r\n if (!normalized) {\r\n throw new Error(`Missing AAD component: ${label}`);\r\n }\r\n if (normalized.includes(':')) {\r\n throw new Error(`AAD component must not contain ':': ${label}`);\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction asBufferSource(bytes: Uint8Array): BufferSource {\r\n return bytes as unknown as BufferSource;\r\n}\r\n\r\n// ============ Type Definitions ============\r\n\r\n/**\r\n * ML-KEM-768 key pair\r\n */\r\nexport interface PQKeyPair {\r\n /** Base64-encoded ML-KEM-768 public key (1184 bytes) */\r\n publicKey: string;\r\n /** Base64-encoded ML-KEM-768 secret key (2400 bytes) */\r\n secretKey: string;\r\n}\r\n\r\n/**\r\n * Combined hybrid key pair with both PQ and classical keys\r\n */\r\nexport interface HybridKeyPair {\r\n /** Base64-encoded ML-KEM-768 public key */\r\n pqPublicKey: string;\r\n /** Base64-encoded ML-KEM-768 secret key */\r\n pqSecretKey: string;\r\n /** JWK string of RSA-4096 public key */\r\n rsaPublicKey: string;\r\n /** JWK string of RSA-4096 private key */\r\n rsaPrivateKey: string;\r\n}\r\n\r\ninterface ParsedHybridCiphertext {\r\n pqCiphertext: Uint8Array;\r\n rsaCiphertext: Uint8Array;\r\n iv: Uint8Array;\r\n aesCiphertext: Uint8Array;\r\n}\r\n"]}
@@ -0,0 +1,133 @@
1
+ import { AES_GCM_TAG_LENGTH, AES_GCM_IV_LENGTH } from './chunk-BUFRR5PB.js';
2
+ import { bytesToBase64, base64ToBytes, utf8ToBytes, bytesToUtf8 } from './chunk-JSKIWIEC.js';
3
+ import { getCryptoProvider, subtle } from './chunk-CYIGDF63.js';
4
+ import { DisInvalidArgumentError, DisDecryptionError } from './chunk-MJO7IJZC.js';
5
+
6
+ // src/aead/index.ts
7
+ function aad(value) {
8
+ return value ? utf8ToBytes(value) : void 0;
9
+ }
10
+ async function encryptBytes(plaintextBytes, key, associatedData) {
11
+ const iv = new Uint8Array(AES_GCM_IV_LENGTH);
12
+ getCryptoProvider().getRandomValues(iv);
13
+ const additionalData = aad(associatedData);
14
+ let ciphertextBytes = null;
15
+ let combined = null;
16
+ try {
17
+ const ciphertext = await subtle().encrypt(
18
+ {
19
+ name: "AES-GCM",
20
+ iv,
21
+ tagLength: AES_GCM_TAG_LENGTH,
22
+ ...additionalData && { additionalData }
23
+ },
24
+ key,
25
+ plaintextBytes
26
+ );
27
+ ciphertextBytes = new Uint8Array(ciphertext);
28
+ combined = new Uint8Array(iv.length + ciphertextBytes.byteLength);
29
+ combined.set(iv, 0);
30
+ combined.set(ciphertextBytes, iv.length);
31
+ return bytesToBase64(combined);
32
+ } finally {
33
+ iv.fill(0);
34
+ additionalData?.fill(0);
35
+ ciphertextBytes?.fill(0);
36
+ combined?.fill(0);
37
+ }
38
+ }
39
+ async function decryptBytes(encryptedBase64, key, associatedData) {
40
+ const combined = base64ToBytes(encryptedBase64);
41
+ if (combined.length <= AES_GCM_IV_LENGTH) {
42
+ combined.fill(0);
43
+ throw new DisInvalidArgumentError("Invalid encrypted data");
44
+ }
45
+ const iv = combined.slice(0, AES_GCM_IV_LENGTH);
46
+ const ciphertext = combined.slice(AES_GCM_IV_LENGTH);
47
+ const additionalData = aad(associatedData);
48
+ try {
49
+ const plaintext = await subtle().decrypt(
50
+ {
51
+ name: "AES-GCM",
52
+ iv,
53
+ tagLength: AES_GCM_TAG_LENGTH,
54
+ ...additionalData && { additionalData }
55
+ },
56
+ key,
57
+ ciphertext
58
+ );
59
+ return new Uint8Array(plaintext);
60
+ } catch {
61
+ throw new DisDecryptionError();
62
+ } finally {
63
+ combined.fill(0);
64
+ iv.fill(0);
65
+ ciphertext.fill(0);
66
+ additionalData?.fill(0);
67
+ }
68
+ }
69
+ async function importAesGcmRawKey(keyBytes, usages) {
70
+ return subtle().importKey(
71
+ "raw",
72
+ keyBytes,
73
+ { name: "AES-GCM" },
74
+ false,
75
+ usages
76
+ );
77
+ }
78
+ async function generateAesGcmKey(usages = ["encrypt", "decrypt"], extractable = false) {
79
+ return subtle().generateKey({ name: "AES-GCM", length: 256 }, extractable, usages);
80
+ }
81
+ async function aesGcmEncrypt(key, nonce, plaintext, associatedData) {
82
+ const cryptoKey = key instanceof Uint8Array ? await importAesGcmRawKey(key, ["encrypt"]) : key;
83
+ const ciphertext = await subtle().encrypt(
84
+ {
85
+ name: "AES-GCM",
86
+ iv: nonce,
87
+ tagLength: AES_GCM_TAG_LENGTH,
88
+ ...associatedData && { additionalData: associatedData }
89
+ },
90
+ cryptoKey,
91
+ plaintext
92
+ );
93
+ return new Uint8Array(ciphertext);
94
+ }
95
+ async function aesGcmDecrypt(key, nonce, ciphertext, associatedData) {
96
+ const cryptoKey = key instanceof Uint8Array ? await importAesGcmRawKey(key, ["decrypt"]) : key;
97
+ try {
98
+ const plaintext = await subtle().decrypt(
99
+ {
100
+ name: "AES-GCM",
101
+ iv: nonce,
102
+ tagLength: AES_GCM_TAG_LENGTH,
103
+ ...associatedData && { additionalData: associatedData }
104
+ },
105
+ cryptoKey,
106
+ ciphertext
107
+ );
108
+ return new Uint8Array(plaintext);
109
+ } catch {
110
+ throw new DisDecryptionError();
111
+ }
112
+ }
113
+ async function encryptString(plaintext, key, associatedData) {
114
+ const plaintextBytes = utf8ToBytes(plaintext);
115
+ try {
116
+ return await encryptBytes(plaintextBytes, key, associatedData);
117
+ } finally {
118
+ plaintextBytes.fill(0);
119
+ }
120
+ }
121
+ async function decryptString(encryptedBase64, key, associatedData) {
122
+ let plaintextBytes = null;
123
+ try {
124
+ plaintextBytes = await decryptBytes(encryptedBase64, key, associatedData);
125
+ return bytesToUtf8(plaintextBytes);
126
+ } finally {
127
+ plaintextBytes?.fill(0);
128
+ }
129
+ }
130
+
131
+ export { aesGcmDecrypt, aesGcmEncrypt, decryptBytes, decryptString, encryptBytes, encryptString, generateAesGcmKey, importAesGcmRawKey };
132
+ //# sourceMappingURL=chunk-U65A4HIY.js.map
133
+ //# sourceMappingURL=chunk-U65A4HIY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/aead/index.ts"],"names":[],"mappings":"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","file":"chunk-U65A4HIY.js","sourcesContent":["/**\r\n * dis-aead — authenticated encryption with associated data.\r\n *\r\n * Primitive: AES-256-GCM via WebCrypto. Output format is\r\n * `base64(IV(12) || ciphertext || authTag(16))`, byte-compatible with Singra\r\n * Vault. A fresh random 96-bit IV is generated per call. Associated data (AAD)\r\n * is authenticated but not stored; the same AAD must be supplied on decrypt,\r\n * which lets callers bind ciphertext to a context (e.g. an entry id) and defeat\r\n * ciphertext-swap attacks.\r\n */\r\n\r\nimport { subtle, getCryptoProvider } from '../core/provider.js';\r\nimport {\r\n base64ToBytes,\r\n bytesToBase64,\r\n bytesToUtf8,\r\n utf8ToBytes,\r\n} from '../core/encoding.js';\r\nimport { AES_GCM_IV_LENGTH, AES_GCM_TAG_LENGTH } from '../core/constants.js';\r\nimport { DisDecryptionError, DisInvalidArgumentError } from '../core/errors.js';\r\n\r\nfunction aad(value?: string): Uint8Array | undefined {\r\n return value ? utf8ToBytes(value) : undefined;\r\n}\r\n\r\n/** Encrypts bytes with AES-256-GCM. Caller still owns/wipes `plaintextBytes`. */\r\nexport async function encryptBytes(\r\n plaintextBytes: Uint8Array,\r\n key: CryptoKey,\r\n associatedData?: string,\r\n): Promise<string> {\r\n const iv = new Uint8Array(AES_GCM_IV_LENGTH);\r\n getCryptoProvider().getRandomValues(iv);\r\n const additionalData = aad(associatedData);\r\n let ciphertextBytes: Uint8Array | null = null;\r\n let combined: Uint8Array | null = null;\r\n try {\r\n const ciphertext = await subtle().encrypt(\r\n {\r\n name: 'AES-GCM',\r\n iv,\r\n tagLength: AES_GCM_TAG_LENGTH,\r\n ...(additionalData && { additionalData }),\r\n },\r\n key,\r\n plaintextBytes as BufferSource,\r\n );\r\n ciphertextBytes = new Uint8Array(ciphertext);\r\n combined = new Uint8Array(iv.length + ciphertextBytes.byteLength);\r\n combined.set(iv, 0);\r\n combined.set(ciphertextBytes, iv.length);\r\n return bytesToBase64(combined);\r\n } finally {\r\n iv.fill(0);\r\n additionalData?.fill(0);\r\n ciphertextBytes?.fill(0);\r\n combined?.fill(0);\r\n }\r\n}\r\n\r\n/** Decrypts AES-256-GCM bytes. Returned buffer is secret — caller must wipe it. */\r\nexport async function decryptBytes(\r\n encryptedBase64: string,\r\n key: CryptoKey,\r\n associatedData?: string,\r\n): Promise<Uint8Array> {\r\n const combined = base64ToBytes(encryptedBase64);\r\n if (combined.length <= AES_GCM_IV_LENGTH) {\r\n combined.fill(0);\r\n throw new DisInvalidArgumentError('Invalid encrypted data');\r\n }\r\n const iv = combined.slice(0, AES_GCM_IV_LENGTH);\r\n const ciphertext = combined.slice(AES_GCM_IV_LENGTH);\r\n const additionalData = aad(associatedData);\r\n try {\r\n const plaintext = await subtle().decrypt(\r\n {\r\n name: 'AES-GCM',\r\n iv,\r\n tagLength: AES_GCM_TAG_LENGTH,\r\n ...(additionalData && { additionalData }),\r\n },\r\n key,\r\n ciphertext as BufferSource,\r\n );\r\n return new Uint8Array(plaintext);\r\n } catch {\r\n // Do not distinguish wrong-key / tampered / AAD-mismatch (no oracle).\r\n throw new DisDecryptionError();\r\n } finally {\r\n combined.fill(0);\r\n iv.fill(0);\r\n ciphertext.fill(0);\r\n additionalData?.fill(0);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Raw-mode AES-GCM\r\n//\r\n// The high-level helpers above own the IV and bundle `base64(IV || ct)`. Some\r\n// Singra surfaces instead manage the nonce themselves and store the nonce and\r\n// ciphertext as separate fields (op-log records, snapshots), bind binary AAD,\r\n// or use a generated non-extractable wrapping key (local secret store). These\r\n// primitives expose AES-256-GCM at that lower level while keeping all WebCrypto\r\n// access inside DIS. Tag length is pinned to 128 bits.\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Imports raw key bytes as an AES-GCM key with the given usages. */\r\nexport async function importAesGcmRawKey(\r\n keyBytes: Uint8Array,\r\n usages: KeyUsage[],\r\n): Promise<CryptoKey> {\r\n return subtle().importKey(\r\n 'raw',\r\n keyBytes as BufferSource,\r\n { name: 'AES-GCM' },\r\n false,\r\n usages,\r\n );\r\n}\r\n\r\n/** Generates a fresh non-extractable AES-256-GCM key. */\r\nexport async function generateAesGcmKey(\r\n usages: KeyUsage[] = ['encrypt', 'decrypt'],\r\n extractable = false,\r\n): Promise<CryptoKey> {\r\n return subtle().generateKey({ name: 'AES-GCM', length: 256 }, extractable, usages);\r\n}\r\n\r\n/**\r\n * AES-256-GCM encrypt with a caller-supplied nonce and optional binary AAD.\r\n * Returns raw `ciphertext || authTag` bytes (no nonce prefix). `key` may be a\r\n * raw 32-byte array or an already-imported `CryptoKey`.\r\n */\r\nexport async function aesGcmEncrypt(\r\n key: CryptoKey | Uint8Array,\r\n nonce: Uint8Array,\r\n plaintext: Uint8Array,\r\n associatedData?: Uint8Array,\r\n): Promise<Uint8Array> {\r\n const cryptoKey = key instanceof Uint8Array ? await importAesGcmRawKey(key, ['encrypt']) : key;\r\n const ciphertext = await subtle().encrypt(\r\n {\r\n name: 'AES-GCM',\r\n iv: nonce as BufferSource,\r\n tagLength: AES_GCM_TAG_LENGTH,\r\n ...(associatedData && { additionalData: associatedData as BufferSource }),\r\n },\r\n cryptoKey,\r\n plaintext as BufferSource,\r\n );\r\n return new Uint8Array(ciphertext);\r\n}\r\n\r\n/**\r\n * AES-256-GCM decrypt with a caller-supplied nonce and optional binary AAD.\r\n * `ciphertext` is raw `ciphertext || authTag` bytes. Throws\r\n * {@link DisDecryptionError} on any failure (wrong key / tamper / AAD mismatch)\r\n * without distinguishing the cause.\r\n */\r\nexport async function aesGcmDecrypt(\r\n key: CryptoKey | Uint8Array,\r\n nonce: Uint8Array,\r\n ciphertext: Uint8Array,\r\n associatedData?: Uint8Array,\r\n): Promise<Uint8Array> {\r\n const cryptoKey = key instanceof Uint8Array ? await importAesGcmRawKey(key, ['decrypt']) : key;\r\n try {\r\n const plaintext = await subtle().decrypt(\r\n {\r\n name: 'AES-GCM',\r\n iv: nonce as BufferSource,\r\n tagLength: AES_GCM_TAG_LENGTH,\r\n ...(associatedData && { additionalData: associatedData as BufferSource }),\r\n },\r\n cryptoKey,\r\n ciphertext as BufferSource,\r\n );\r\n return new Uint8Array(plaintext);\r\n } catch {\r\n throw new DisDecryptionError();\r\n }\r\n}\r\n\r\n/** Encrypts a UTF-8 string. The intermediate plaintext bytes are wiped. */\r\nexport async function encryptString(\r\n plaintext: string,\r\n key: CryptoKey,\r\n associatedData?: string,\r\n): Promise<string> {\r\n const plaintextBytes = utf8ToBytes(plaintext);\r\n try {\r\n return await encryptBytes(plaintextBytes, key, associatedData);\r\n } finally {\r\n plaintextBytes.fill(0);\r\n }\r\n}\r\n\r\n/** Decrypts to a UTF-8 string. The intermediate plaintext bytes are wiped. */\r\nexport async function decryptString(\r\n encryptedBase64: string,\r\n key: CryptoKey,\r\n associatedData?: string,\r\n): Promise<string> {\r\n let plaintextBytes: Uint8Array | null = null;\r\n try {\r\n plaintextBytes = await decryptBytes(encryptedBase64, key, associatedData);\r\n return bytesToUtf8(plaintextBytes);\r\n } finally {\r\n plaintextBytes?.fill(0);\r\n }\r\n}\r\n"]}
@@ -0,0 +1,20 @@
1
+ export { C as CryptoProvider, D as DisDecryptionError, a as DisError, b as DisErrorCode, c as DisIntegrityError, d as DisInvalidArgumentError, e as DisLegacyPayloadError, f as DisUnsupportedFormatVersionError, g as getCryptoProvider, s as setCryptoProvider, h as subtle } from '../errors-C79jA9vX.js';
2
+ export { b as base64ToBytes, a as base64UrlToBytes, c as bytesToBase64, d as bytesToBase64Url, e as bytesToHex, f as bytesToUtf8, g as concatBytes, u as utf8ToBytes } from '../encoding-B-cb7Duu.js';
3
+
4
+ /**
5
+ * Cryptographic constants shared across DIS modules.
6
+ *
7
+ * These values are part of the on-the-wire / on-disk format contract. Changing
8
+ * any released constant is a breaking format change and MUST be expressed as a
9
+ * new format version, never an in-place edit.
10
+ */
11
+ /** AES-GCM IV length in bytes (96 bits — the recommended GCM nonce size). */
12
+ declare const AES_GCM_IV_LENGTH = 12;
13
+ /** AES-GCM authentication tag length in bits. */
14
+ declare const AES_GCM_TAG_LENGTH = 128;
15
+ /** Symmetric key length in bytes (AES-256). */
16
+ declare const AES_KEY_LENGTH = 32;
17
+ /** Salt length in bytes (128 bits) for password-based key derivation. */
18
+ declare const KDF_SALT_LENGTH = 16;
19
+
20
+ export { AES_GCM_IV_LENGTH, AES_GCM_TAG_LENGTH, AES_KEY_LENGTH, KDF_SALT_LENGTH };
@@ -0,0 +1,6 @@
1
+ export { AES_GCM_IV_LENGTH, AES_GCM_TAG_LENGTH, AES_KEY_LENGTH, KDF_SALT_LENGTH } from '../chunk-BUFRR5PB.js';
2
+ export { base64ToBytes, base64UrlToBytes, bytesToBase64, bytesToBase64Url, bytesToHex, bytesToUtf8, concatBytes, utf8ToBytes } from '../chunk-JSKIWIEC.js';
3
+ export { getCryptoProvider, setCryptoProvider, subtle } from '../chunk-CYIGDF63.js';
4
+ export { DisDecryptionError, DisError, DisIntegrityError, DisInvalidArgumentError, DisLegacyPayloadError, DisUnsupportedFormatVersionError } from '../chunk-MJO7IJZC.js';
5
+ //# sourceMappingURL=index.js.map
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}