raz-encrypt 2.1.0 → 2.3.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 (49) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +448 -442
  3. package/dist/canonicalJson.d.ts +0 -15
  4. package/dist/canonicalJson.js +13 -73
  5. package/dist/canonicalJson.js.map +1 -1
  6. package/dist/core.d.ts +2 -4
  7. package/dist/core.js +1 -3
  8. package/dist/core.js.map +1 -1
  9. package/dist/crypto/classical.d.ts +0 -2
  10. package/dist/crypto/classical.js +0 -4
  11. package/dist/crypto/classical.js.map +1 -1
  12. package/dist/crypto/frameCipher.js +2 -8
  13. package/dist/crypto/frameCipher.js.map +1 -1
  14. package/dist/crypto/hybrid.d.ts +8 -95
  15. package/dist/crypto/hybrid.js +49 -374
  16. package/dist/crypto/hybrid.js.map +1 -1
  17. package/dist/crypto/nodeHybrid.d.ts +4 -6
  18. package/dist/crypto/nodeHybrid.js +2 -3
  19. package/dist/crypto/nodeHybrid.js.map +1 -1
  20. package/dist/crypto/pqc.d.ts +2 -7
  21. package/dist/crypto/pqc.js +4 -13
  22. package/dist/crypto/pqc.js.map +1 -1
  23. package/dist/crypto/ratchet.js +0 -5
  24. package/dist/crypto/ratchet.js.map +1 -1
  25. package/dist/fileCrypto.d.ts +2 -44
  26. package/dist/fileCrypto.js +28 -197
  27. package/dist/fileCrypto.js.map +1 -1
  28. package/dist/identity.d.ts +4 -69
  29. package/dist/identity.js +12 -111
  30. package/dist/identity.js.map +1 -1
  31. package/dist/index.d.ts +7 -8
  32. package/dist/index.js +4 -4
  33. package/dist/index.js.map +1 -1
  34. package/dist/store.d.ts +5 -42
  35. package/dist/store.js +22 -254
  36. package/dist/store.js.map +1 -1
  37. package/dist/trust.d.ts +2 -143
  38. package/dist/trust.js +27 -376
  39. package/dist/trust.js.map +1 -1
  40. package/package.json +69 -62
  41. package/dist/crypto/confirmedSession.d.ts +0 -47
  42. package/dist/crypto/confirmedSession.js +0 -84
  43. package/dist/crypto/confirmedSession.js.map +0 -1
  44. package/dist/crypto/frameSession.d.ts +0 -40
  45. package/dist/crypto/frameSession.js +0 -96
  46. package/dist/crypto/frameSession.js.map +0 -1
  47. package/dist/passphrase.d.ts +0 -27
  48. package/dist/passphrase.js +0 -69
  49. package/dist/passphrase.js.map +0 -1
@@ -1,18 +1,3 @@
1
- /**
2
- * Canonical JSON per RFC 8785 (JCS): no whitespace, object keys sorted by
3
- * UTF-16 code unit, ECMAScript number and string serialization — so the same
4
- * logical document always hashes to the same value regardless of key order
5
- * on the wire.
6
- *
7
- * Unlike a bare `JSON.stringify`, this rejects (with a `TypeError` naming the
8
- * offending path) every value that JSON cannot represent faithfully, rather
9
- * than silently collapsing it into something else. Two different in-memory
10
- * documents must never canonicalize to the same bytes (ADR 0012):
11
- * `undefined`, `NaN`, `±Infinity`, `BigInt`, functions, symbols, sparse
12
- * arrays, circular references, lone surrogates, and anything that is not a
13
- * plain object / array / string / finite number / boolean / null (`Map`,
14
- * `Set`, `Date`, typed arrays, class instances, ...).
15
- */
16
1
  export declare function canonicalize(value: unknown): string;
17
2
  /** The document hash every signature is made over. */
18
3
  export declare function hashDocument(value: unknown): string;
@@ -1,82 +1,22 @@
1
1
  import { sha512 } from "@noble/hashes/sha2.js";
2
2
  import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
3
3
  /**
4
- * Canonical JSON per RFC 8785 (JCS): no whitespace, object keys sorted by
5
- * UTF-16 code unit, ECMAScript number and string serialization — so the same
6
- * logical document always hashes to the same value regardless of key order
7
- * on the wire.
8
- *
9
- * Unlike a bare `JSON.stringify`, this rejects (with a `TypeError` naming the
10
- * offending path) every value that JSON cannot represent faithfully, rather
11
- * than silently collapsing it into something else. Two different in-memory
12
- * documents must never canonicalize to the same bytes (ADR 0012):
13
- * `undefined`, `NaN`, `±Infinity`, `BigInt`, functions, symbols, sparse
14
- * arrays, circular references, lone surrogates, and anything that is not a
15
- * plain object / array / string / finite number / boolean / null (`Map`,
16
- * `Set`, `Date`, typed arrays, class instances, ...).
4
+ * Deterministic JSON serialization (object keys sorted recursively) so the
5
+ * same logical document always hashes to the same value regardless of key
6
+ * order on the wire.
17
7
  */
18
- export function canonicalize(value) {
19
- return serialize(value, "$", new Set());
20
- }
21
- function fail(path, what) {
22
- throw new TypeError(`canonicalize: ${what} at ${path} cannot be represented as canonical JSON`);
23
- }
24
- function serialize(value, path, ancestors) {
25
- switch (typeof value) {
26
- case "string":
27
- return serializeString(value, path);
28
- case "number":
29
- if (!Number.isFinite(value))
30
- fail(path, `non-finite number (${String(value)})`);
31
- // ECMAScript Number::toString is exactly what RFC 8785 §3.2.2.3 mandates
32
- // (including "-0" -> "0").
33
- return JSON.stringify(value);
34
- case "boolean":
35
- return value ? "true" : "false";
36
- case "object":
37
- break;
38
- default:
39
- return fail(path, typeof value === "undefined" ? "undefined" : `${typeof value}`);
40
- }
41
- if (value === null)
42
- return "null";
43
- const obj = value;
44
- if (ancestors.has(obj))
45
- fail(path, "circular reference");
46
- ancestors.add(obj);
47
- try {
48
- if (Array.isArray(obj)) {
49
- const parts = [];
50
- for (let i = 0; i < obj.length; i++) {
51
- if (!(i in obj))
52
- fail(`${path}[${i}]`, "hole in sparse array");
53
- parts.push(serialize(obj[i], `${path}[${i}]`, ancestors));
54
- }
55
- return `[${parts.join(",")}]`;
56
- }
57
- const proto = Object.getPrototypeOf(obj);
58
- if (proto !== Object.prototype && proto !== null) {
59
- fail(path, `non-plain object (${proto.constructor?.name ?? "unknown"})`);
60
- }
61
- const record = obj;
62
- // Default sort() compares UTF-16 code units, which is the RFC 8785 order.
63
- const keys = Object.keys(record).sort();
64
- const parts = keys.map((key) => `${serializeString(key, `${path}.${key}`)}:${serialize(record[key], `${path}.${key}`, ancestors)}`);
65
- return `{${parts.join(",")}}`;
66
- }
67
- finally {
68
- ancestors.delete(obj);
8
+ function sortKeysDeep(value) {
9
+ if (Array.isArray(value))
10
+ return value.map(sortKeysDeep);
11
+ if (value !== null && typeof value === "object") {
12
+ return Object.fromEntries(Object.keys(value)
13
+ .sort()
14
+ .map((key) => [key, sortKeysDeep(value[key])]));
69
15
  }
16
+ return value;
70
17
  }
71
- // High surrogate not followed by a low one, or a low surrogate not preceded by a high one.
72
- const LONE_SURROGATE = /[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;
73
- function serializeString(value, path) {
74
- // RFC 8785 requires I-JSON: strings must be well-formed UTF-16. A lone
75
- // surrogate has no UTF-8 encoding, so two distinct strings would otherwise
76
- // both turn into U+FFFD when hashed.
77
- if (LONE_SURROGATE.test(value))
78
- fail(path, "string with a lone surrogate");
79
- return JSON.stringify(value);
18
+ export function canonicalize(value) {
19
+ return JSON.stringify(sortKeysDeep(value));
80
20
  }
81
21
  /** The document hash every signature is made over. */
82
22
  export function hashDocument(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"canonicalJson.js","sourceRoot":"","sources":["../src/canonicalJson.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"canonicalJson.js","sourceRoot":"","sources":["../src/canonicalJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;;;GAIG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC;aAC1C,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,YAAY,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAC9E,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC"}
package/dist/core.d.ts CHANGED
@@ -10,8 +10,8 @@
10
10
  * included, fs-backed versions of the same logic — this module is the
11
11
  * un-wired core they're built from, not a separate implementation.
12
12
  */
13
- export { createResponderHandshakeCore as createResponderHandshake, decryptFromCore as decryptFrom, DecryptionError, encryptForCore as encryptFor, establishSessionInitiatorCore as establishSessionInitiator, establishSessionResponderCore as establishSessionResponder, HandshakeVerificationError, makeKeyConfirmation, verifyKeyConfirmation, MalformedHandshakeMessageError, ReplayedBoxError, signCore as sign, UntrustedPartyError, verifyCore as verify, } from "./crypto/hybrid.js";
14
- export type { BoxReplayInfo, Certificate, DecryptDeps, EncryptedBox, HandshakeRole, HandshakeSignature, HandshakeTranscript, InitiatorHandshakeMessage, InitiatorSessionResult, LogDeps, ResponderHandshakeInit, ResponderHandshakeMessage, ResponderHandshakeSecrets, ResponderSessionResult, SessionKeys, SignOptions, TrustDeps, TrustStatus, VerifyDeps, VerifyFailureReason, VerifyResult, } from "./crypto/hybrid.js";
13
+ export { createResponderHandshakeCore as createResponderHandshake, decryptFromCore as decryptFrom, encryptForCore as encryptFor, establishSessionInitiatorCore as establishSessionInitiator, establishSessionResponderCore as establishSessionResponder, HandshakeVerificationError, signCore as sign, UntrustedPartyError, verifyCore as verify, } from "./crypto/hybrid.js";
14
+ export type { Certificate, EncryptedBox, HandshakeSignature, InitiatorHandshakeMessage, InitiatorSessionResult, LogDeps, ResponderHandshakeInit, ResponderHandshakeMessage, ResponderHandshakeSecrets, ResponderSessionResult, SessionKeys, SignOptions, TrustDeps, TrustStatus, VerifyDeps, VerifyFailureReason, VerifyResult, } from "./crypto/hybrid.js";
15
15
  export { generateClassicalKeypair, classicalSharedSecret, classicalSign, classicalVerify } from "./crypto/classical.js";
16
16
  export type { ClassicalKeypair } from "./crypto/classical.js";
17
17
  export { generatePqcKemKeypair, generatePqcSignKeypair, pqcDecapsulate, pqcEncapsulate, pqcSign, pqcVerify, } from "./crypto/pqc.js";
@@ -20,8 +20,6 @@ export { canonicalize, hashDocument } from "./canonicalJson.js";
20
20
  export { fingerprint } from "./fingerprint.js";
21
21
  export { decryptFrame, encryptFrame, FrameDecryptionError } from "./crypto/frameCipher.js";
22
22
  export type { EncryptedFrame } from "./crypto/frameCipher.js";
23
- export { createFrameChannels, FrameCounterError, FrameReceiver, FrameSender } from "./crypto/frameSession.js";
24
- export { ConfirmedSession, UnconfirmedSessionError } from "./crypto/confirmedSession.js";
25
23
  export { CHAIN_INFO_INITIATOR_TO_RESPONDER, CHAIN_INFO_RESPONDER_TO_INITIATOR, ML_KEM_STEP_CADENCE, performEcdhStep, performKemStep, ratchetChainKey, seedChainKey, } from "./crypto/ratchet.js";
26
24
  export type { AsymmetricStepResult, ChainStep } from "./crypto/ratchet.js";
27
25
  export type { Identity, PublicCard } from "./identity.js";
package/dist/core.js CHANGED
@@ -10,13 +10,11 @@
10
10
  * included, fs-backed versions of the same logic — this module is the
11
11
  * un-wired core they're built from, not a separate implementation.
12
12
  */
13
- export { createResponderHandshakeCore as createResponderHandshake, decryptFromCore as decryptFrom, DecryptionError, encryptForCore as encryptFor, establishSessionInitiatorCore as establishSessionInitiator, establishSessionResponderCore as establishSessionResponder, HandshakeVerificationError, makeKeyConfirmation, verifyKeyConfirmation, MalformedHandshakeMessageError, ReplayedBoxError, signCore as sign, UntrustedPartyError, verifyCore as verify, } from "./crypto/hybrid.js";
13
+ export { createResponderHandshakeCore as createResponderHandshake, decryptFromCore as decryptFrom, encryptForCore as encryptFor, establishSessionInitiatorCore as establishSessionInitiator, establishSessionResponderCore as establishSessionResponder, HandshakeVerificationError, signCore as sign, UntrustedPartyError, verifyCore as verify, } from "./crypto/hybrid.js";
14
14
  export { generateClassicalKeypair, classicalSharedSecret, classicalSign, classicalVerify } from "./crypto/classical.js";
15
15
  export { generatePqcKemKeypair, generatePqcSignKeypair, pqcDecapsulate, pqcEncapsulate, pqcSign, pqcVerify, } from "./crypto/pqc.js";
16
16
  export { canonicalize, hashDocument } from "./canonicalJson.js";
17
17
  export { fingerprint } from "./fingerprint.js";
18
18
  export { decryptFrame, encryptFrame, FrameDecryptionError } from "./crypto/frameCipher.js";
19
- export { createFrameChannels, FrameCounterError, FrameReceiver, FrameSender } from "./crypto/frameSession.js";
20
- export { ConfirmedSession, UnconfirmedSessionError } from "./crypto/confirmedSession.js";
21
19
  export { CHAIN_INFO_INITIATOR_TO_RESPONDER, CHAIN_INFO_RESPONDER_TO_INITIATOR, ML_KEM_STEP_CADENCE, performEcdhStep, performKemStep, ratchetChainKey, seedChainKey, } from "./crypto/ratchet.js";
22
20
  //# sourceMappingURL=core.js.map
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,4BAA4B,IAAI,wBAAwB,EACxD,eAAe,IAAI,WAAW,EAC9B,eAAe,EACf,cAAc,IAAI,UAAU,EAC5B,6BAA6B,IAAI,yBAAyB,EAC1D,6BAA6B,IAAI,yBAAyB,EAC1D,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,8BAA8B,EAC9B,gBAAgB,EAChB,QAAQ,IAAI,IAAI,EAChB,mBAAmB,EACnB,UAAU,IAAI,MAAM,GACrB,MAAM,oBAAoB,CAAC;AAyB5B,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,OAAO,EACP,SAAS,GACV,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEzF,OAAO,EACL,iCAAiC,EACjC,iCAAiC,EACjC,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,4BAA4B,IAAI,wBAAwB,EACxD,eAAe,IAAI,WAAW,EAC9B,cAAc,IAAI,UAAU,EAC5B,6BAA6B,IAAI,yBAAyB,EAC1D,6BAA6B,IAAI,yBAAyB,EAC1D,0BAA0B,EAC1B,QAAQ,IAAI,IAAI,EAChB,mBAAmB,EACnB,UAAU,IAAI,MAAM,GACrB,MAAM,oBAAoB,CAAC;AAqB5B,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,OAAO,EACP,SAAS,GACV,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG3F,OAAO,EACL,iCAAiC,EACjC,iCAAiC,EACjC,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,qBAAqB,CAAC"}
@@ -8,5 +8,3 @@ export declare function classicalSign(message: Uint8Array, secretKey: Uint8Array
8
8
  export declare function classicalVerify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
9
9
  /** ECDH shared secret between our secret key and their public key. */
10
10
  export declare function classicalSharedSecret(secretKey: Uint8Array, theirPublicKey: Uint8Array): Uint8Array;
11
- /** True iff `keypair`'s two fields are the exact byte lengths p384's own keygen produces — a cheap sanity check for key material sourced from somewhere this library doesn't control (e.g. a caller-supplied KeyStore, issue #38). */
12
- export declare function isValidClassicalKeypairShape(keypair: ClassicalKeypair): boolean;
@@ -18,8 +18,4 @@ export function classicalVerify(signature, message, publicKey) {
18
18
  export function classicalSharedSecret(secretKey, theirPublicKey) {
19
19
  return p384.getSharedSecret(secretKey, theirPublicKey);
20
20
  }
21
- /** True iff `keypair`'s two fields are the exact byte lengths p384's own keygen produces — a cheap sanity check for key material sourced from somewhere this library doesn't control (e.g. a caller-supplied KeyStore, issue #38). */
22
- export function isValidClassicalKeypairShape(keypair) {
23
- return keypair.secretKey.length === p384.lengths.secretKey && keypair.publicKey.length === p384.lengths.publicKey;
24
- }
25
21
  //# sourceMappingURL=classical.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"classical.js","sourceRoot":"","sources":["../../src/crypto/classical.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAO7C,yEAAyE;AACzE,MAAM,UAAU,wBAAwB;IACtC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmB,EAAE,SAAqB;IACtE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAqB,EAAE,OAAmB,EAAE,SAAqB;IAC/F,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,SAAqB,EAAE,cAA0B;IACrF,OAAO,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AACzD,CAAC;AAED,sOAAsO;AACtO,MAAM,UAAU,4BAA4B,CAAC,OAAyB;IACpE,OAAO,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;AACpH,CAAC"}
1
+ {"version":3,"file":"classical.js","sourceRoot":"","sources":["../../src/crypto/classical.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAO7C,yEAAyE;AACzE,MAAM,UAAU,wBAAwB;IACtC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmB,EAAE,SAAqB;IACtE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAqB,EAAE,OAAmB,EAAE,SAAqB;IAC/F,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,SAAqB,EAAE,cAA0B;IACrF,OAAO,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AACzD,CAAC"}
@@ -1,9 +1,5 @@
1
1
  import { gcm } from "@noble/ciphers/aes.js";
2
2
  import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
3
- // Prefer FrameSender/FrameReceiver (./frameSession.ts), which own the counter so
4
- // it cannot be reused by mistake; use these raw functions only if you must manage
5
- // counters yourself.
6
- //
7
3
  // The per-frame AEAD used to wrap every message sent under a session key
8
4
  // established by establishSessionInitiatorCore/establishSessionResponderCore
9
5
  // (see hybrid.ts) — one directional key, reused across many frames, so the
@@ -24,10 +20,8 @@ export class FrameDecryptionError extends Error {
24
20
  }
25
21
  /** Encodes `counter` as a 96-bit nonce: 4 zero bytes + an 8-byte big-endian counter (2^64 frames is far beyond any realistic session). */
26
22
  function counterToNonce(counter) {
27
- // isSafeInteger, not isInteger: above 2^53 distinct counters can round to
28
- // the same double, which would silently reuse a nonce.
29
- if (!Number.isSafeInteger(counter) || counter < 0) {
30
- throw new Error(`Frame counter must be a non-negative safe integer (0 to 2^53-1), got ${counter}.`);
23
+ if (!Number.isInteger(counter) || counter < 0) {
24
+ throw new Error(`Frame counter must be a non-negative integer, got ${counter}.`);
31
25
  }
32
26
  const nonce = new Uint8Array(NONCE_LENGTH);
33
27
  let value = BigInt(counter);
@@ -1 +1 @@
1
- {"version":3,"file":"frameCipher.js","sourceRoot":"","sources":["../../src/crypto/frameCipher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEhE,iFAAiF;AACjF,kFAAkF;AAClF,qBAAqB;AACrB,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,gBAAgB;AAEhB,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;QACE,KAAK,CAAC,+FAA+F,CAAC,CAAC;QACvG,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AASD,0IAA0I;AAC1I,SAAS,cAAc,CAAC,OAAe;IACrC,0EAA0E;IAC1E,uDAAuD;IACvD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,wEAAwE,OAAO,GAAG,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,IAAI,YAAY,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;QACtE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;QACjC,KAAK,KAAK,EAAE,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,GAAe,EAAE,OAAe,EAAE,SAAqB,EAAE,GAAgB;IACpG,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAe,EAAE,KAAqB,EAAE,GAAgB;IACnF,IAAI,CAAC;QACH,OAAO,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,oBAAoB,EAAE,CAAC;IACnC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"frameCipher.js","sourceRoot":"","sources":["../../src/crypto/frameCipher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEhE,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,gBAAgB;AAEhB,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;QACE,KAAK,CAAC,+FAA+F,CAAC,CAAC;QACvG,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AASD,0IAA0I;AAC1I,SAAS,cAAc,CAAC,OAAe;IACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,qDAAqD,OAAO,GAAG,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,IAAI,YAAY,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;QACtE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;QACjC,KAAK,KAAK,EAAE,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,GAAe,EAAE,OAAe,EAAE,SAAqB,EAAE,GAAgB;IACpG,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAe,EAAE,KAAqB,EAAE,GAAgB;IACnF,IAAI,CAAC;QACH,OAAO,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,oBAAoB,EAAE,CAAC;IACnC,CAAC;AACH,CAAC"}
@@ -7,23 +7,6 @@ declare const ALGORITHMS: {
7
7
  export declare class UntrustedPartyError extends Error {
8
8
  constructor(alias: string);
9
9
  }
10
- /** Thrown by decryptFromCore for a structurally-malformed EncryptedBox or a failed AEAD decryption — both mean "this box is unusable", so one error class covers both causes. */
11
- export declare class DecryptionError extends Error {
12
- constructor(message: string);
13
- }
14
- /**
15
- * True only for the exact canonical format `new Date().toISOString()` itself
16
- * produces — the one format this codebase ever actually writes. A round-trip
17
- * check (not a regex, not bare `Date.parse`) catches wrong formats, non-ISO
18
- * strings `Date.parse` would otherwise accept (implementation-defined beyond
19
- * strict ISO-8601), AND calendar-overflow values some engines silently roll
20
- * forward (e.g. a Feb 30th) — all in one comparison: any mismatch, whatever
21
- * the cause, fails the round-trip (ADR 0010). Exported so other modules that
22
- * define their own timestamp fields (e.g. trust.ts's rotation/revocation
23
- * documents) can hold them to the same strict standard instead of each
24
- * re-deriving their own looser check.
25
- */
26
- export declare function isValidIsoInstant(value: string): boolean;
27
10
  export interface Certificate {
28
11
  documentHash: string;
29
12
  classicalSignature: string;
@@ -35,14 +18,6 @@ export interface Certificate {
35
18
  pqcSignPublicKey: string;
36
19
  };
37
20
  signedAt: string;
38
- /**
39
- * Certificate format. 2 (what sign() writes) means the signatures also cover
40
- * `signer.alias` and `signedAt`; absent means a legacy certificate whose
41
- * signatures cover only the document hash and expiry, so those two fields
42
- * are unauthenticated there. A v2 certificate stripped of this field does
43
- * not become a valid legacy one: its signatures are over the v2 message.
44
- */
45
- version?: 2;
46
21
  /** Absent = permanent proof, valid indefinitely (the default, unchanged behavior). */
47
22
  expiresAt?: string;
48
23
  }
@@ -50,7 +25,7 @@ export interface SignOptions {
50
25
  /** If set, verify() rejects this certificate as "expired" once this ISO timestamp has passed. */
51
26
  expiresAt?: string;
52
27
  }
53
- export type VerifyFailureReason = "untrusted-signer" | "revoked-signer" | "hash-mismatch" | "classical-signature-mismatch" | "pqc-signature-mismatch" | "expired" | "malformed-certificate";
28
+ export type VerifyFailureReason = "untrusted-signer" | "revoked-signer" | "hash-mismatch" | "classical-signature-mismatch" | "pqc-signature-mismatch" | "expired";
54
29
  export type VerifyResult = {
55
30
  valid: true;
56
31
  } | {
@@ -93,57 +68,24 @@ export declare function signCore(identity: Identity, document: unknown, options?
93
68
  */
94
69
  export declare function verifyCore(identity: Identity, document: unknown, certificate: Certificate, deps: VerifyDeps): Promise<VerifyResult>;
95
70
  export interface EncryptedBox {
96
- /** Always 2. Version 1 boxes (1.x, unsigned, no context binding) are rejected. */
97
- version: 2;
98
- /** 16 random bytes, hex. Unique per box; use it to detect replays. */
99
- id: string;
100
- /** When the sender sealed the box (ISO-8601, covered by the signature). */
101
- signedAt: string;
102
71
  kemCipherText: string;
103
72
  nonce: string;
104
73
  ciphertext: string;
105
- /** The sender's dual (ECDSA-P384 + ML-DSA-87) signature over everything above and both party fingerprints. */
106
- signature: {
107
- classicalSignature: string;
108
- pqcSignature: string;
109
- };
110
- }
111
- /** Thrown by decryptFromCore when the caller's `isReplay` hook reports the (otherwise valid) box was already seen. */
112
- export declare class ReplayedBoxError extends Error {
113
- constructor(id: string);
114
- }
115
- /** What the replay hook is told about a box that has already passed signature verification. */
116
- export interface BoxReplayInfo {
117
- id: string;
118
- signedAt: string;
119
- senderFingerprint: string;
120
- }
121
- /** decryptFromCore's dependencies: trust, log, and an optional replay check (return true to reject the box). */
122
- export interface DecryptDeps extends TrustDeps {
123
- isReplay?: (info: BoxReplayInfo) => boolean | Promise<boolean>;
124
74
  }
125
75
  /**
126
- * Encrypts `data` for `counterpart` (box v2, ADR 0018). The key comes from
127
- * ECDH-P384 and an ML-KEM-1024 encapsulation, combined by HKDF-SHA384 with a
128
- * salt that binds both parties and every public value in the box. AES-256-GCM
129
- * authenticates the same context as AAD, and the sender dual-signs the box so
130
- * it cannot be forged by the recipient or anyone else. Throws
131
- * UntrustedPartyError unless `deps.checkTrust(counterpart)` reports "trusted".
132
- *
133
- * There is still NO forward secrecy: the ECDH half uses long-term keys. Use a
134
- * session handshake for anything that needs it.
76
+ * Encrypts `data` for `counterpart` using a symmetric key derived from BOTH
77
+ * an ECDH-P384 exchange and an ML-KEM-1024 encapsulation (HKDF-SHA384
78
+ * combines the two secrets), then AES-256-GCM. Throws UntrustedPartyError
79
+ * unless `deps.checkTrust(counterpart)` reports "trusted".
135
80
  */
136
81
  export declare function encryptForCore(identity: Identity, counterpart: PublicCard, data: unknown, deps: TrustDeps): Promise<EncryptedBox>;
137
82
  /**
138
83
  * Decrypts a box produced by `encryptFor`. `counterpart` is the sender's
139
84
  * public card. Throws UntrustedPartyError unless `deps.checkTrust(counterpart)`
140
- * reports "trusted". The sender's signature and the recipient binding are
141
- * verified BEFORE any decapsulation or decryption; a v1 box, a box sealed for
142
- * someone else, or a box not signed by `counterpart` is a DecryptionError. If
143
- * `deps.isReplay` is given it is consulted only after the signature checks
144
- * out, and a true result throws ReplayedBoxError.
85
+ * reports "trusted" — this stops a caller from accidentally decrypting "as
86
+ * if" a message came from someone they never actually trusted.
145
87
  */
146
- export declare function decryptFromCore<T = unknown>(identity: Identity, counterpart: PublicCard, box: EncryptedBox, deps: DecryptDeps): Promise<T>;
88
+ export declare function decryptFromCore<T = unknown>(identity: Identity, counterpart: PublicCard, box: EncryptedBox, deps: TrustDeps): Promise<T>;
147
89
  export interface SessionKeys {
148
90
  /** AES-256-GCM key for frames sent by the initiator, decrypted by the responder. */
149
91
  initiatorToResponder: Uint8Array;
@@ -212,35 +154,6 @@ export interface ResponderSessionResult {
212
154
  export declare class HandshakeVerificationError extends Error {
213
155
  constructor(message: string);
214
156
  }
215
- /** Thrown for a structurally-malformed handshake message (non-hex fields) — distinct from HandshakeVerificationError, which means the shape was fine but the signature didn't check out. */
216
- export declare class MalformedHandshakeMessageError extends Error {
217
- constructor(message: string);
218
- }
219
- /** The four handshake artifacts a confirmation tag is computed over — exactly what both sides hold once the handshake completes. */
220
- export interface HandshakeTranscript {
221
- initiatorCard: PublicCard;
222
- responderCard: PublicCard;
223
- responderMessage: ResponderHandshakeMessage;
224
- initiatorMessage: InitiatorHandshakeMessage;
225
- }
226
- export type HandshakeRole = "initiator" | "responder";
227
- /**
228
- * The tag to send the counterpart as proof you derived the same secrets:
229
- * HMAC-SHA384, keyed by the handshake's `confirmationKey`, over the full
230
- * transcript and YOUR role (hex, 96 characters). Folding the role in means
231
- * your own tag can never be replayed back to you as the counterpart's.
232
- * Send it only after the handshake call returned, and treat the connection
233
- * as unauthenticated until `verifyKeyConfirmation` succeeds on the tag you
234
- * receive.
235
- */
236
- export declare function makeKeyConfirmation(confirmationKey: Uint8Array, role: HandshakeRole, transcript: HandshakeTranscript): string;
237
- /**
238
- * Checks the tag received from the counterpart. Pass the COUNTERPART's role
239
- * (an initiator verifies "responder"). Returns false — never throws — for a
240
- * wrong tag, a malformed one (any non-string, odd length, non-hex, wrong
241
- * length, uppercase) or an unusable key/role, and compares in constant time.
242
- */
243
- export declare function verifyKeyConfirmation(confirmationKey: Uint8Array, counterpartRole: HandshakeRole, transcript: HandshakeTranscript, tag: unknown): boolean;
244
157
  /**
245
158
  * First step of the handshake, run by the connection's responder: generates
246
159
  * one fresh, single-use ECDH-P384 keypair and one fresh, single-use