@omnituum/pqc-shared 0.4.0 → 0.6.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.
- package/dist/crypto/index.cjs +91 -54
- package/dist/crypto/index.d.cts +43 -11
- package/dist/crypto/index.d.ts +43 -11
- package/dist/crypto/index.js +87 -55
- package/dist/{decrypt-eSHlbh1j.d.cts → decrypt-O1iqFIDL.d.cts} +80 -6
- package/dist/{decrypt-eSHlbh1j.d.ts → decrypt-O1iqFIDL.d.ts} +80 -6
- package/dist/fs/index.cjs +286 -147
- package/dist/fs/index.d.cts +28 -7
- package/dist/fs/index.d.ts +28 -7
- package/dist/fs/index.js +277 -147
- package/dist/index.cjs +368 -229
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +362 -230
- package/dist/{integrity-ByMp24VA.d.cts → integrity-BkBDrHA-.d.cts} +12 -4
- package/dist/{integrity-BPvNsC50.d.ts → integrity-DsFJv5c-.d.ts} +12 -4
- package/dist/{types-Dx_AFqow.d.cts → types-DmnVueAY.d.cts} +15 -5
- package/dist/{types-Dx_AFqow.d.ts → types-DmnVueAY.d.ts} +15 -5
- package/dist/utils/index.cjs +7 -10
- package/dist/utils/index.d.cts +2 -2
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +7 -10
- package/dist/vault/index.cjs +8 -11
- package/dist/vault/index.d.cts +2 -2
- package/dist/vault/index.d.ts +2 -2
- package/dist/vault/index.js +8 -11
- package/package.json +19 -25
- package/src/crypto/dilithium.ts +4 -4
- package/src/crypto/hybrid.ts +182 -80
- package/src/crypto/index.ts +8 -1
- package/src/crypto/kyber.ts +20 -0
- package/src/fs/decrypt.ts +145 -68
- package/src/fs/encrypt.ts +161 -112
- package/src/fs/format.ts +110 -15
- package/src/fs/index.ts +4 -0
- package/src/fs/types.ts +77 -6
- package/src/index.ts +9 -0
- package/src/utils/integrity.ts +16 -15
- package/src/vault/manager.ts +1 -1
- package/src/version.ts +29 -7
package/dist/crypto/index.cjs
CHANGED
|
@@ -201,6 +201,11 @@ function deriveKeyFromShared(shared, salt, info) {
|
|
|
201
201
|
return hkdfSha256(shared, { salt: u8(salt), info: u8(info), length: 32 });
|
|
202
202
|
}
|
|
203
203
|
var KYBER_SUITE = "ML-KEM-1024-FIPS203";
|
|
204
|
+
var KYBER_PUBLIC_KEY_SIZE = 1568;
|
|
205
|
+
var KYBER_SECRET_KEY_SIZE = 3168;
|
|
206
|
+
var KYBER_CIPHERTEXT_SIZE = 1568;
|
|
207
|
+
var KYBER_SHARED_SECRET_SIZE = 32;
|
|
208
|
+
var KYBER_SEED_SIZE = 64;
|
|
204
209
|
async function isKyberAvailable() {
|
|
205
210
|
return true;
|
|
206
211
|
}
|
|
@@ -256,8 +261,7 @@ async function loadDilithium() {
|
|
|
256
261
|
const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa.js');
|
|
257
262
|
dilithiumModule = ml_dsa65;
|
|
258
263
|
return dilithiumModule;
|
|
259
|
-
} catch
|
|
260
|
-
console.warn("[Dilithium] Failed to load @noble/post-quantum:", e);
|
|
264
|
+
} catch {
|
|
261
265
|
return null;
|
|
262
266
|
}
|
|
263
267
|
}
|
|
@@ -275,8 +279,7 @@ async function generateDilithiumKeypair() {
|
|
|
275
279
|
publicB64: toB64(kp.publicKey),
|
|
276
280
|
secretB64: toB64(kp.secretKey)
|
|
277
281
|
};
|
|
278
|
-
} catch
|
|
279
|
-
console.warn("[Dilithium] Key generation failed:", e);
|
|
282
|
+
} catch {
|
|
280
283
|
return null;
|
|
281
284
|
}
|
|
282
285
|
}
|
|
@@ -345,11 +348,13 @@ var DILITHIUM_SECRET_KEY_SIZE = 4032;
|
|
|
345
348
|
var DILITHIUM_SIGNATURE_SIZE = 3309;
|
|
346
349
|
var DILITHIUM_ALGORITHM = "ML-DSA-65";
|
|
347
350
|
var ENVELOPE_VERSION = envelopeRegistry.OMNI_VERSIONS.HYBRID_V1;
|
|
351
|
+
var ENVELOPE_VERSION_V2 = envelopeRegistry.OMNI_VERSIONS.HYBRID_V2;
|
|
348
352
|
var ENVELOPE_VERSION_LEGACY = envelopeRegistry.DEPRECATED_VERSIONS.PQC_DEMO_HYBRID_V1;
|
|
349
|
-
var
|
|
353
|
+
var ENVELOPE_SUITE_V2 = "x25519+mlkem1024";
|
|
350
354
|
var ENVELOPE_AEAD = "xsalsa20poly1305";
|
|
351
355
|
var SUPPORTED_ENVELOPE_VERSIONS = [
|
|
352
356
|
ENVELOPE_VERSION,
|
|
357
|
+
ENVELOPE_VERSION_V2,
|
|
353
358
|
ENVELOPE_VERSION_LEGACY
|
|
354
359
|
];
|
|
355
360
|
var VersionMismatchError = class extends Error {
|
|
@@ -381,7 +386,6 @@ async function generateHybridIdentity(name) {
|
|
|
381
386
|
const x25519 = generateX25519Keypair();
|
|
382
387
|
const kyber = await generateKyberKeypair();
|
|
383
388
|
if (!kyber) {
|
|
384
|
-
console.error("Kyber key generation failed - library not available");
|
|
385
389
|
return null;
|
|
386
390
|
}
|
|
387
391
|
return {
|
|
@@ -423,49 +427,74 @@ function getSecretKeys(identity) {
|
|
|
423
427
|
kyberSecB64: identity.kyberSecB64
|
|
424
428
|
};
|
|
425
429
|
}
|
|
430
|
+
function combinedKekV2(kyberShared, x25519Shared, x25519EpkHex, kyberKemCtB64) {
|
|
431
|
+
const ikm = new Uint8Array(kyberShared.length + x25519Shared.length);
|
|
432
|
+
ikm.set(kyberShared, 0);
|
|
433
|
+
ikm.set(x25519Shared, kyberShared.length);
|
|
434
|
+
try {
|
|
435
|
+
return hkdfFlex(ikm, "omnituum/hybrid-v2", `wrap-ck|${x25519EpkHex}|${kyberKemCtB64}`);
|
|
436
|
+
} finally {
|
|
437
|
+
ikm.fill(0);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
426
440
|
async function hybridEncrypt(plaintext, recipientPublicKeys, sender) {
|
|
427
441
|
const pt = typeof plaintext === "string" ? textEncoder.encode(plaintext) : plaintext;
|
|
428
442
|
const CK = rand32();
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
443
|
+
try {
|
|
444
|
+
const contentNonce = rand24();
|
|
445
|
+
const ciphertext = nacl__default.default.secretbox(pt, contentNonce, CK);
|
|
446
|
+
const x25519EphKp = nacl__default.default.box.keyPair();
|
|
447
|
+
const recipientX25519Pk = fromHex(recipientPublicKeys.x25519PubHex);
|
|
448
|
+
const x25519Shared = nacl__default.default.scalarMult(x25519EphKp.secretKey, recipientX25519Pk);
|
|
449
|
+
const x25519EpkHex = toHex(x25519EphKp.publicKey);
|
|
450
|
+
const kyberResult = await kyberEncapsulate(recipientPublicKeys.kyberPubB64);
|
|
451
|
+
const kyberKemCtB64 = b64(kyberResult.ciphertext);
|
|
452
|
+
const kek = combinedKekV2(kyberResult.sharedSecret, x25519Shared, x25519EpkHex, kyberKemCtB64);
|
|
453
|
+
const ckWrapNonce = rand24();
|
|
454
|
+
const ckWrapped = nacl__default.default.secretbox(CK, ckWrapNonce, kek);
|
|
455
|
+
kek.fill(0);
|
|
456
|
+
x25519Shared.fill(0);
|
|
457
|
+
kyberResult.sharedSecret.fill(0);
|
|
458
|
+
x25519EphKp.secretKey.fill(0);
|
|
459
|
+
return {
|
|
460
|
+
v: ENVELOPE_VERSION_V2,
|
|
461
|
+
suite: ENVELOPE_SUITE_V2,
|
|
462
|
+
aead: ENVELOPE_AEAD,
|
|
463
|
+
x25519Epk: x25519EpkHex,
|
|
464
|
+
kyberKemCt: kyberKemCtB64,
|
|
465
|
+
ckWrap: {
|
|
466
|
+
nonce: b64(ckWrapNonce),
|
|
467
|
+
wrapped: b64(ckWrapped)
|
|
468
|
+
},
|
|
469
|
+
contentNonce: b64(contentNonce),
|
|
470
|
+
ciphertext: b64(ciphertext),
|
|
471
|
+
meta: {
|
|
472
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
473
|
+
senderName: sender?.name,
|
|
474
|
+
senderId: sender?.id
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
} finally {
|
|
478
|
+
CK.fill(0);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async function unwrapCkV2(envelope, secretKeys) {
|
|
482
|
+
const kyberShared = await kyberDecapsulate(envelope.kyberKemCt, secretKeys.kyberSecB64);
|
|
483
|
+
const ephPk = fromHex(envelope.x25519Epk);
|
|
484
|
+
const sk = fromHex(secretKeys.x25519SecHex);
|
|
485
|
+
const x25519Shared = nacl__default.default.scalarMult(sk, ephPk);
|
|
486
|
+
const kek = combinedKekV2(kyberShared, x25519Shared, envelope.x25519Epk, envelope.kyberKemCt);
|
|
487
|
+
kyberShared.fill(0);
|
|
488
|
+
x25519Shared.fill(0);
|
|
489
|
+
const CK = nacl__default.default.secretbox.open(ub64(envelope.ckWrap.wrapped), ub64(envelope.ckWrap.nonce), kek);
|
|
490
|
+
kek.fill(0);
|
|
491
|
+
if (!CK) {
|
|
492
|
+
throw new Error("Could not unwrap content key \u2014 combined-KEK authentication failed");
|
|
493
|
+
}
|
|
494
|
+
return CK;
|
|
463
495
|
}
|
|
464
|
-
async function
|
|
465
|
-
const version = envelope.v;
|
|
466
|
-
assertEnvelopeVersion(version);
|
|
496
|
+
async function unwrapCkV1(envelope, secretKeys, saltPrefix) {
|
|
467
497
|
let CK = null;
|
|
468
|
-
const saltPrefix = version === "pqc-demo.hybrid.v1" ? "pqc-demo" : "omnituum";
|
|
469
498
|
try {
|
|
470
499
|
const kyberShared = await kyberDecapsulate(envelope.kyberKemCt, secretKeys.kyberSecB64);
|
|
471
500
|
const kyberKek = hkdfFlex(kyberShared, `${saltPrefix}/kyber`, "wrap-ck");
|
|
@@ -474,11 +503,7 @@ async function hybridDecrypt(envelope, secretKeys) {
|
|
|
474
503
|
ub64(envelope.kyberWrap.nonce),
|
|
475
504
|
kyberKek
|
|
476
505
|
);
|
|
477
|
-
|
|
478
|
-
console.log("[Hybrid] Decrypted using Kyber (post-quantum)");
|
|
479
|
-
}
|
|
480
|
-
} catch (e) {
|
|
481
|
-
console.warn("[Hybrid] Kyber decapsulation failed:", e);
|
|
506
|
+
} catch {
|
|
482
507
|
}
|
|
483
508
|
if (!CK) {
|
|
484
509
|
try {
|
|
@@ -491,21 +516,28 @@ async function hybridDecrypt(envelope, secretKeys) {
|
|
|
491
516
|
ub64(envelope.x25519Wrap.nonce),
|
|
492
517
|
x25519Kek
|
|
493
518
|
);
|
|
494
|
-
|
|
495
|
-
console.log("[Hybrid] Decrypted using X25519 (classical)");
|
|
496
|
-
}
|
|
497
|
-
} catch (e) {
|
|
498
|
-
console.warn("[Hybrid] X25519 decryption failed:", e);
|
|
519
|
+
} catch {
|
|
499
520
|
}
|
|
500
521
|
}
|
|
501
522
|
if (!CK) {
|
|
502
523
|
throw new Error("Could not unwrap content key with either algorithm");
|
|
503
524
|
}
|
|
525
|
+
return CK;
|
|
526
|
+
}
|
|
527
|
+
async function hybridDecrypt(envelope, secretKeys) {
|
|
528
|
+
const version = envelope.v;
|
|
529
|
+
assertEnvelopeVersion(version);
|
|
530
|
+
const CK = version === ENVELOPE_VERSION_V2 ? await unwrapCkV2(envelope, secretKeys) : await unwrapCkV1(
|
|
531
|
+
envelope,
|
|
532
|
+
secretKeys,
|
|
533
|
+
version === "pqc-demo.hybrid.v1" ? "pqc-demo" : "omnituum"
|
|
534
|
+
);
|
|
504
535
|
const pt = nacl__default.default.secretbox.open(
|
|
505
536
|
ub64(envelope.ciphertext),
|
|
506
537
|
ub64(envelope.contentNonce),
|
|
507
538
|
CK
|
|
508
539
|
);
|
|
540
|
+
CK.fill(0);
|
|
509
541
|
if (!pt) {
|
|
510
542
|
throw new Error("Content authentication failed");
|
|
511
543
|
}
|
|
@@ -689,6 +721,11 @@ exports.HKDF_SHA256_MAX_OUTPUT = HKDF_SHA256_MAX_OUTPUT;
|
|
|
689
721
|
exports.HKDF_SHA256_OUTPUT_SIZE = HKDF_SHA256_OUTPUT_SIZE;
|
|
690
722
|
exports.HKDF_SHA512_MAX_OUTPUT = HKDF_SHA512_MAX_OUTPUT;
|
|
691
723
|
exports.HKDF_SHA512_OUTPUT_SIZE = HKDF_SHA512_OUTPUT_SIZE;
|
|
724
|
+
exports.KYBER_CIPHERTEXT_SIZE = KYBER_CIPHERTEXT_SIZE;
|
|
725
|
+
exports.KYBER_PUBLIC_KEY_SIZE = KYBER_PUBLIC_KEY_SIZE;
|
|
726
|
+
exports.KYBER_SECRET_KEY_SIZE = KYBER_SECRET_KEY_SIZE;
|
|
727
|
+
exports.KYBER_SEED_SIZE = KYBER_SEED_SIZE;
|
|
728
|
+
exports.KYBER_SHARED_SECRET_SIZE = KYBER_SHARED_SECRET_SIZE;
|
|
692
729
|
exports.KYBER_SUITE = KYBER_SUITE;
|
|
693
730
|
exports.POLY1305_TAG_SIZE = POLY1305_TAG_SIZE;
|
|
694
731
|
exports.SECRETBOX_KEY_SIZE = SECRETBOX_KEY_SIZE;
|
package/dist/crypto/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OmniHybridV1 } from '@omnituum/envelope-registry';
|
|
1
|
+
import { OmniHybridV2, OmniHybridV1 } from '@omnituum/envelope-registry';
|
|
2
2
|
import * as _noble_ciphers_utils_js from '@noble/ciphers/utils.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -35,6 +35,16 @@ interface KyberEncapsulation {
|
|
|
35
35
|
/** Canonical suite identifier for new material produced by this package. */
|
|
36
36
|
declare const KYBER_SUITE: "ML-KEM-1024-FIPS203";
|
|
37
37
|
type KyberSuite = typeof KYBER_SUITE;
|
|
38
|
+
/** ML-KEM-1024 public key size (bytes). */
|
|
39
|
+
declare const KYBER_PUBLIC_KEY_SIZE = 1568;
|
|
40
|
+
/** ML-KEM-1024 secret key size (bytes). */
|
|
41
|
+
declare const KYBER_SECRET_KEY_SIZE = 3168;
|
|
42
|
+
/** ML-KEM-1024 ciphertext size (bytes). */
|
|
43
|
+
declare const KYBER_CIPHERTEXT_SIZE = 1568;
|
|
44
|
+
/** ML-KEM-1024 shared-secret size (bytes). */
|
|
45
|
+
declare const KYBER_SHARED_SECRET_SIZE = 32;
|
|
46
|
+
/** Seed size accepted by `generateKyberKeypairFromSeed` (bytes). */
|
|
47
|
+
declare const KYBER_SEED_SIZE = 64;
|
|
38
48
|
/**
|
|
39
49
|
* @deprecated Always returns true. Retained for API stability across the
|
|
40
50
|
* 0.3.x → 0.4.x cut. The noble backend is statically imported and always
|
|
@@ -67,10 +77,16 @@ declare function kyberUnwrapKey(sharedSecret: Uint8Array, nonceB64: string, wrap
|
|
|
67
77
|
*
|
|
68
78
|
* Post-quantum secure hybrid encryption combining:
|
|
69
79
|
* - X25519 ECDH (classical, proven security)
|
|
70
|
-
* -
|
|
80
|
+
* - ML-KEM-1024 (post-quantum, FIPS 203, NIST Level 5)
|
|
71
81
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
82
|
+
* v2 (current write format): the content key is wrapped once, under a KEK
|
|
83
|
+
* derived from BOTH shared secrets (HKDF(ss_mlkem || ss_x25519) with
|
|
84
|
+
* transcript binding) — both key exchanges must succeed to decrypt, so
|
|
85
|
+
* breaking either primitive alone is insufficient.
|
|
86
|
+
*
|
|
87
|
+
* v1 (read-only legacy): wrapped the key independently under each
|
|
88
|
+
* primitive; either secret alone sufficed. Kept only for decrypting
|
|
89
|
+
* existing envelopes — see the 2026-07-05 security audit.
|
|
74
90
|
*/
|
|
75
91
|
|
|
76
92
|
interface HybridIdentity {
|
|
@@ -106,12 +122,21 @@ interface HybridSecretKeys {
|
|
|
106
122
|
kyberSecB64: string;
|
|
107
123
|
}
|
|
108
124
|
|
|
109
|
-
type
|
|
125
|
+
type HybridEnvelopeV1 = Omit<OmniHybridV1, 'meta'> & {
|
|
110
126
|
meta: OmniHybridV1['meta'] & {
|
|
111
127
|
senderName?: string;
|
|
112
128
|
senderId?: string;
|
|
113
129
|
};
|
|
114
130
|
};
|
|
131
|
+
|
|
132
|
+
type HybridEnvelopeV2 = Omit<OmniHybridV2, 'meta'> & {
|
|
133
|
+
meta: OmniHybridV2['meta'] & {
|
|
134
|
+
senderName?: string;
|
|
135
|
+
senderId?: string;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
/** Any hybrid envelope this module can decrypt. */
|
|
139
|
+
type HybridEnvelope = HybridEnvelopeV1 | HybridEnvelopeV2;
|
|
115
140
|
/**
|
|
116
141
|
* Generate a new hybrid identity with both X25519 and Kyber keys.
|
|
117
142
|
*/
|
|
@@ -129,7 +154,12 @@ declare function getPublicKeys(identity: HybridIdentity): HybridPublicKeys;
|
|
|
129
154
|
*/
|
|
130
155
|
declare function getSecretKeys(identity: HybridIdentity): HybridSecretKeys;
|
|
131
156
|
/**
|
|
132
|
-
* Encrypt a message using hybrid X25519 +
|
|
157
|
+
* Encrypt a message using hybrid X25519 + ML-KEM-1024 encryption (v2).
|
|
158
|
+
*
|
|
159
|
+
* The content key is wrapped exactly once, under a KEK derived from both
|
|
160
|
+
* shared secrets together — breaking either primitive alone is insufficient
|
|
161
|
+
* to unwrap. (v1 wrapped the key independently under each primitive, which
|
|
162
|
+
* reduced security to min(X25519, ML-KEM); v1 is now read-only legacy.)
|
|
133
163
|
*
|
|
134
164
|
* @param plaintext - Message to encrypt (string or bytes)
|
|
135
165
|
* @param recipientPublicKeys - Recipient's public keys
|
|
@@ -138,12 +168,14 @@ declare function getSecretKeys(identity: HybridIdentity): HybridSecretKeys;
|
|
|
138
168
|
declare function hybridEncrypt(plaintext: string | Uint8Array, recipientPublicKeys: HybridPublicKeys, sender?: {
|
|
139
169
|
name?: string;
|
|
140
170
|
id?: string;
|
|
141
|
-
}): Promise<
|
|
171
|
+
}): Promise<HybridEnvelopeV2>;
|
|
142
172
|
/**
|
|
143
|
-
* Decrypt a hybrid envelope.
|
|
173
|
+
* Decrypt a hybrid envelope (v2, v1, or legacy pqc-demo).
|
|
144
174
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
175
|
+
* v2: the content key is unwrapped from a single AND-combined KEK — both
|
|
176
|
+
* ML-KEM and X25519 secrets are required, and any failure is fatal.
|
|
177
|
+
* v1/legacy: read-only compatibility path (either secret suffices — the
|
|
178
|
+
* defect v2 exists to fix).
|
|
147
179
|
*
|
|
148
180
|
* @param envelope - Encrypted envelope
|
|
149
181
|
* @param secretKeys - Recipient's secret keys
|
|
@@ -631,4 +663,4 @@ declare const BOX_KEY_SIZE: number;
|
|
|
631
663
|
/** NaCl box nonce size (24 bytes) */
|
|
632
664
|
declare const BOX_NONCE_SIZE: number;
|
|
633
665
|
|
|
634
|
-
export { BLAKE3_BLOCK_SIZE, BLAKE3_KEY_LENGTH, BLAKE3_OUTPUT_LENGTH, BOX_KEY_SIZE, BOX_NONCE_SIZE, type Blake3Options, type BoxPayload, CHACHA20_KEY_SIZE, CHACHA20_NONCE_SIZE, type ChaChaPayload, type ClassicalWrap, DILITHIUM_ALGORITHM, DILITHIUM_PUBLIC_KEY_SIZE, DILITHIUM_SECRET_KEY_SIZE, DILITHIUM_SIGNATURE_SIZE, type DilithiumKeypair, type DilithiumKeypairB64, type DilithiumSignature, HKDF_SHA256_MAX_OUTPUT, HKDF_SHA256_OUTPUT_SIZE, HKDF_SHA512_MAX_OUTPUT, HKDF_SHA512_OUTPUT_SIZE, type HkdfHash, type HkdfOptions, type HybridEnvelope, type HybridIdentity, type HybridPublicKeys, type HybridSecretKeys, KYBER_SUITE, type KyberEncapsulation, type KyberKeypair, type KyberKeypairB64, type KyberSuite, POLY1305_TAG_SIZE, SECRETBOX_KEY_SIZE, SECRETBOX_NONCE_SIZE, SECRETBOX_OVERHEAD, type SecretboxPayload, type X25519Keypair, type X25519KeypairHex, XCHACHA20_NONCE_SIZE, assertLen, b64, blake3, blake3DeriveKey, blake3Hex, blake3Mac, boxDecrypt, boxEncrypt, boxUnwrapWithX25519, boxWrapWithX25519, chaCha20Poly1305Decrypt, chaCha20Poly1305Encrypt, createChaCha20Poly1305, createXChaCha20Poly1305, deriveKeyFromShared, dilithiumSign, dilithiumSignRaw, dilithiumVerify, dilithiumVerifyRaw, fromB64, fromHex, generateDilithiumKeypair, generateDilithiumKeypairFromSeed, generateHybridIdentity, generateKyberKeypair, generateKyberKeypairFromSeed, generateX25519Keypair, generateX25519KeypairFromSeed, getPublicKeys, getSecretKeys, hkdfDerive, hkdfExpand, hkdfExtract, hkdfSha256, hkdfSplitForNoise, hkdfTripleSplitForNoise, hybridDecrypt, hybridDecryptToString, hybridEncrypt, isDilithiumAvailable, isKyberAvailable, kyberDecapsulate, kyberEncapsulate, kyberUnwrapKey, kyberWrapKey, rand12, rand24, rand32, randN, rotateHybridIdentity, secretboxDecrypt, secretboxDecryptString, secretboxEncrypt, secretboxEncryptString, secretboxOpenRaw, secretboxRaw, sha256, sha256String, textDecoder, textEncoder, toB64, toHex, u8, ub64, x25519SharedSecret, xChaCha20Poly1305Decrypt, xChaCha20Poly1305Encrypt };
|
|
666
|
+
export { BLAKE3_BLOCK_SIZE, BLAKE3_KEY_LENGTH, BLAKE3_OUTPUT_LENGTH, BOX_KEY_SIZE, BOX_NONCE_SIZE, type Blake3Options, type BoxPayload, CHACHA20_KEY_SIZE, CHACHA20_NONCE_SIZE, type ChaChaPayload, type ClassicalWrap, DILITHIUM_ALGORITHM, DILITHIUM_PUBLIC_KEY_SIZE, DILITHIUM_SECRET_KEY_SIZE, DILITHIUM_SIGNATURE_SIZE, type DilithiumKeypair, type DilithiumKeypairB64, type DilithiumSignature, HKDF_SHA256_MAX_OUTPUT, HKDF_SHA256_OUTPUT_SIZE, HKDF_SHA512_MAX_OUTPUT, HKDF_SHA512_OUTPUT_SIZE, type HkdfHash, type HkdfOptions, type HybridEnvelope, type HybridEnvelopeV1, type HybridEnvelopeV2, type HybridIdentity, type HybridPublicKeys, type HybridSecretKeys, KYBER_CIPHERTEXT_SIZE, KYBER_PUBLIC_KEY_SIZE, KYBER_SECRET_KEY_SIZE, KYBER_SEED_SIZE, KYBER_SHARED_SECRET_SIZE, KYBER_SUITE, type KyberEncapsulation, type KyberKeypair, type KyberKeypairB64, type KyberSuite, POLY1305_TAG_SIZE, SECRETBOX_KEY_SIZE, SECRETBOX_NONCE_SIZE, SECRETBOX_OVERHEAD, type SecretboxPayload, type X25519Keypair, type X25519KeypairHex, XCHACHA20_NONCE_SIZE, assertLen, b64, blake3, blake3DeriveKey, blake3Hex, blake3Mac, boxDecrypt, boxEncrypt, boxUnwrapWithX25519, boxWrapWithX25519, chaCha20Poly1305Decrypt, chaCha20Poly1305Encrypt, createChaCha20Poly1305, createXChaCha20Poly1305, deriveKeyFromShared, dilithiumSign, dilithiumSignRaw, dilithiumVerify, dilithiumVerifyRaw, fromB64, fromHex, generateDilithiumKeypair, generateDilithiumKeypairFromSeed, generateHybridIdentity, generateKyberKeypair, generateKyberKeypairFromSeed, generateX25519Keypair, generateX25519KeypairFromSeed, getPublicKeys, getSecretKeys, hkdfDerive, hkdfExpand, hkdfExtract, hkdfSha256, hkdfSplitForNoise, hkdfTripleSplitForNoise, hybridDecrypt, hybridDecryptToString, hybridEncrypt, isDilithiumAvailable, isKyberAvailable, kyberDecapsulate, kyberEncapsulate, kyberUnwrapKey, kyberWrapKey, rand12, rand24, rand32, randN, rotateHybridIdentity, secretboxDecrypt, secretboxDecryptString, secretboxEncrypt, secretboxEncryptString, secretboxOpenRaw, secretboxRaw, sha256, sha256String, textDecoder, textEncoder, toB64, toHex, u8, ub64, x25519SharedSecret, xChaCha20Poly1305Decrypt, xChaCha20Poly1305Encrypt };
|
package/dist/crypto/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OmniHybridV1 } from '@omnituum/envelope-registry';
|
|
1
|
+
import { OmniHybridV2, OmniHybridV1 } from '@omnituum/envelope-registry';
|
|
2
2
|
import * as _noble_ciphers_utils_js from '@noble/ciphers/utils.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -35,6 +35,16 @@ interface KyberEncapsulation {
|
|
|
35
35
|
/** Canonical suite identifier for new material produced by this package. */
|
|
36
36
|
declare const KYBER_SUITE: "ML-KEM-1024-FIPS203";
|
|
37
37
|
type KyberSuite = typeof KYBER_SUITE;
|
|
38
|
+
/** ML-KEM-1024 public key size (bytes). */
|
|
39
|
+
declare const KYBER_PUBLIC_KEY_SIZE = 1568;
|
|
40
|
+
/** ML-KEM-1024 secret key size (bytes). */
|
|
41
|
+
declare const KYBER_SECRET_KEY_SIZE = 3168;
|
|
42
|
+
/** ML-KEM-1024 ciphertext size (bytes). */
|
|
43
|
+
declare const KYBER_CIPHERTEXT_SIZE = 1568;
|
|
44
|
+
/** ML-KEM-1024 shared-secret size (bytes). */
|
|
45
|
+
declare const KYBER_SHARED_SECRET_SIZE = 32;
|
|
46
|
+
/** Seed size accepted by `generateKyberKeypairFromSeed` (bytes). */
|
|
47
|
+
declare const KYBER_SEED_SIZE = 64;
|
|
38
48
|
/**
|
|
39
49
|
* @deprecated Always returns true. Retained for API stability across the
|
|
40
50
|
* 0.3.x → 0.4.x cut. The noble backend is statically imported and always
|
|
@@ -67,10 +77,16 @@ declare function kyberUnwrapKey(sharedSecret: Uint8Array, nonceB64: string, wrap
|
|
|
67
77
|
*
|
|
68
78
|
* Post-quantum secure hybrid encryption combining:
|
|
69
79
|
* - X25519 ECDH (classical, proven security)
|
|
70
|
-
* -
|
|
80
|
+
* - ML-KEM-1024 (post-quantum, FIPS 203, NIST Level 5)
|
|
71
81
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
82
|
+
* v2 (current write format): the content key is wrapped once, under a KEK
|
|
83
|
+
* derived from BOTH shared secrets (HKDF(ss_mlkem || ss_x25519) with
|
|
84
|
+
* transcript binding) — both key exchanges must succeed to decrypt, so
|
|
85
|
+
* breaking either primitive alone is insufficient.
|
|
86
|
+
*
|
|
87
|
+
* v1 (read-only legacy): wrapped the key independently under each
|
|
88
|
+
* primitive; either secret alone sufficed. Kept only for decrypting
|
|
89
|
+
* existing envelopes — see the 2026-07-05 security audit.
|
|
74
90
|
*/
|
|
75
91
|
|
|
76
92
|
interface HybridIdentity {
|
|
@@ -106,12 +122,21 @@ interface HybridSecretKeys {
|
|
|
106
122
|
kyberSecB64: string;
|
|
107
123
|
}
|
|
108
124
|
|
|
109
|
-
type
|
|
125
|
+
type HybridEnvelopeV1 = Omit<OmniHybridV1, 'meta'> & {
|
|
110
126
|
meta: OmniHybridV1['meta'] & {
|
|
111
127
|
senderName?: string;
|
|
112
128
|
senderId?: string;
|
|
113
129
|
};
|
|
114
130
|
};
|
|
131
|
+
|
|
132
|
+
type HybridEnvelopeV2 = Omit<OmniHybridV2, 'meta'> & {
|
|
133
|
+
meta: OmniHybridV2['meta'] & {
|
|
134
|
+
senderName?: string;
|
|
135
|
+
senderId?: string;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
/** Any hybrid envelope this module can decrypt. */
|
|
139
|
+
type HybridEnvelope = HybridEnvelopeV1 | HybridEnvelopeV2;
|
|
115
140
|
/**
|
|
116
141
|
* Generate a new hybrid identity with both X25519 and Kyber keys.
|
|
117
142
|
*/
|
|
@@ -129,7 +154,12 @@ declare function getPublicKeys(identity: HybridIdentity): HybridPublicKeys;
|
|
|
129
154
|
*/
|
|
130
155
|
declare function getSecretKeys(identity: HybridIdentity): HybridSecretKeys;
|
|
131
156
|
/**
|
|
132
|
-
* Encrypt a message using hybrid X25519 +
|
|
157
|
+
* Encrypt a message using hybrid X25519 + ML-KEM-1024 encryption (v2).
|
|
158
|
+
*
|
|
159
|
+
* The content key is wrapped exactly once, under a KEK derived from both
|
|
160
|
+
* shared secrets together — breaking either primitive alone is insufficient
|
|
161
|
+
* to unwrap. (v1 wrapped the key independently under each primitive, which
|
|
162
|
+
* reduced security to min(X25519, ML-KEM); v1 is now read-only legacy.)
|
|
133
163
|
*
|
|
134
164
|
* @param plaintext - Message to encrypt (string or bytes)
|
|
135
165
|
* @param recipientPublicKeys - Recipient's public keys
|
|
@@ -138,12 +168,14 @@ declare function getSecretKeys(identity: HybridIdentity): HybridSecretKeys;
|
|
|
138
168
|
declare function hybridEncrypt(plaintext: string | Uint8Array, recipientPublicKeys: HybridPublicKeys, sender?: {
|
|
139
169
|
name?: string;
|
|
140
170
|
id?: string;
|
|
141
|
-
}): Promise<
|
|
171
|
+
}): Promise<HybridEnvelopeV2>;
|
|
142
172
|
/**
|
|
143
|
-
* Decrypt a hybrid envelope.
|
|
173
|
+
* Decrypt a hybrid envelope (v2, v1, or legacy pqc-demo).
|
|
144
174
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
175
|
+
* v2: the content key is unwrapped from a single AND-combined KEK — both
|
|
176
|
+
* ML-KEM and X25519 secrets are required, and any failure is fatal.
|
|
177
|
+
* v1/legacy: read-only compatibility path (either secret suffices — the
|
|
178
|
+
* defect v2 exists to fix).
|
|
147
179
|
*
|
|
148
180
|
* @param envelope - Encrypted envelope
|
|
149
181
|
* @param secretKeys - Recipient's secret keys
|
|
@@ -631,4 +663,4 @@ declare const BOX_KEY_SIZE: number;
|
|
|
631
663
|
/** NaCl box nonce size (24 bytes) */
|
|
632
664
|
declare const BOX_NONCE_SIZE: number;
|
|
633
665
|
|
|
634
|
-
export { BLAKE3_BLOCK_SIZE, BLAKE3_KEY_LENGTH, BLAKE3_OUTPUT_LENGTH, BOX_KEY_SIZE, BOX_NONCE_SIZE, type Blake3Options, type BoxPayload, CHACHA20_KEY_SIZE, CHACHA20_NONCE_SIZE, type ChaChaPayload, type ClassicalWrap, DILITHIUM_ALGORITHM, DILITHIUM_PUBLIC_KEY_SIZE, DILITHIUM_SECRET_KEY_SIZE, DILITHIUM_SIGNATURE_SIZE, type DilithiumKeypair, type DilithiumKeypairB64, type DilithiumSignature, HKDF_SHA256_MAX_OUTPUT, HKDF_SHA256_OUTPUT_SIZE, HKDF_SHA512_MAX_OUTPUT, HKDF_SHA512_OUTPUT_SIZE, type HkdfHash, type HkdfOptions, type HybridEnvelope, type HybridIdentity, type HybridPublicKeys, type HybridSecretKeys, KYBER_SUITE, type KyberEncapsulation, type KyberKeypair, type KyberKeypairB64, type KyberSuite, POLY1305_TAG_SIZE, SECRETBOX_KEY_SIZE, SECRETBOX_NONCE_SIZE, SECRETBOX_OVERHEAD, type SecretboxPayload, type X25519Keypair, type X25519KeypairHex, XCHACHA20_NONCE_SIZE, assertLen, b64, blake3, blake3DeriveKey, blake3Hex, blake3Mac, boxDecrypt, boxEncrypt, boxUnwrapWithX25519, boxWrapWithX25519, chaCha20Poly1305Decrypt, chaCha20Poly1305Encrypt, createChaCha20Poly1305, createXChaCha20Poly1305, deriveKeyFromShared, dilithiumSign, dilithiumSignRaw, dilithiumVerify, dilithiumVerifyRaw, fromB64, fromHex, generateDilithiumKeypair, generateDilithiumKeypairFromSeed, generateHybridIdentity, generateKyberKeypair, generateKyberKeypairFromSeed, generateX25519Keypair, generateX25519KeypairFromSeed, getPublicKeys, getSecretKeys, hkdfDerive, hkdfExpand, hkdfExtract, hkdfSha256, hkdfSplitForNoise, hkdfTripleSplitForNoise, hybridDecrypt, hybridDecryptToString, hybridEncrypt, isDilithiumAvailable, isKyberAvailable, kyberDecapsulate, kyberEncapsulate, kyberUnwrapKey, kyberWrapKey, rand12, rand24, rand32, randN, rotateHybridIdentity, secretboxDecrypt, secretboxDecryptString, secretboxEncrypt, secretboxEncryptString, secretboxOpenRaw, secretboxRaw, sha256, sha256String, textDecoder, textEncoder, toB64, toHex, u8, ub64, x25519SharedSecret, xChaCha20Poly1305Decrypt, xChaCha20Poly1305Encrypt };
|
|
666
|
+
export { BLAKE3_BLOCK_SIZE, BLAKE3_KEY_LENGTH, BLAKE3_OUTPUT_LENGTH, BOX_KEY_SIZE, BOX_NONCE_SIZE, type Blake3Options, type BoxPayload, CHACHA20_KEY_SIZE, CHACHA20_NONCE_SIZE, type ChaChaPayload, type ClassicalWrap, DILITHIUM_ALGORITHM, DILITHIUM_PUBLIC_KEY_SIZE, DILITHIUM_SECRET_KEY_SIZE, DILITHIUM_SIGNATURE_SIZE, type DilithiumKeypair, type DilithiumKeypairB64, type DilithiumSignature, HKDF_SHA256_MAX_OUTPUT, HKDF_SHA256_OUTPUT_SIZE, HKDF_SHA512_MAX_OUTPUT, HKDF_SHA512_OUTPUT_SIZE, type HkdfHash, type HkdfOptions, type HybridEnvelope, type HybridEnvelopeV1, type HybridEnvelopeV2, type HybridIdentity, type HybridPublicKeys, type HybridSecretKeys, KYBER_CIPHERTEXT_SIZE, KYBER_PUBLIC_KEY_SIZE, KYBER_SECRET_KEY_SIZE, KYBER_SEED_SIZE, KYBER_SHARED_SECRET_SIZE, KYBER_SUITE, type KyberEncapsulation, type KyberKeypair, type KyberKeypairB64, type KyberSuite, POLY1305_TAG_SIZE, SECRETBOX_KEY_SIZE, SECRETBOX_NONCE_SIZE, SECRETBOX_OVERHEAD, type SecretboxPayload, type X25519Keypair, type X25519KeypairHex, XCHACHA20_NONCE_SIZE, assertLen, b64, blake3, blake3DeriveKey, blake3Hex, blake3Mac, boxDecrypt, boxEncrypt, boxUnwrapWithX25519, boxWrapWithX25519, chaCha20Poly1305Decrypt, chaCha20Poly1305Encrypt, createChaCha20Poly1305, createXChaCha20Poly1305, deriveKeyFromShared, dilithiumSign, dilithiumSignRaw, dilithiumVerify, dilithiumVerifyRaw, fromB64, fromHex, generateDilithiumKeypair, generateDilithiumKeypairFromSeed, generateHybridIdentity, generateKyberKeypair, generateKyberKeypairFromSeed, generateX25519Keypair, generateX25519KeypairFromSeed, getPublicKeys, getSecretKeys, hkdfDerive, hkdfExpand, hkdfExtract, hkdfSha256, hkdfSplitForNoise, hkdfTripleSplitForNoise, hybridDecrypt, hybridDecryptToString, hybridEncrypt, isDilithiumAvailable, isKyberAvailable, kyberDecapsulate, kyberEncapsulate, kyberUnwrapKey, kyberWrapKey, rand12, rand24, rand32, randN, rotateHybridIdentity, secretboxDecrypt, secretboxDecryptString, secretboxEncrypt, secretboxEncryptString, secretboxOpenRaw, secretboxRaw, sha256, sha256String, textDecoder, textEncoder, toB64, toHex, u8, ub64, x25519SharedSecret, xChaCha20Poly1305Decrypt, xChaCha20Poly1305Encrypt };
|