raz-encrypt 2.3.0 → 2.4.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/LICENSE +21 -21
- package/README.md +488 -448
- package/dist/canonicalJson.d.ts +15 -0
- package/dist/canonicalJson.js +73 -13
- package/dist/canonicalJson.js.map +1 -1
- package/dist/core.d.ts +4 -2
- package/dist/core.js +3 -1
- package/dist/core.js.map +1 -1
- package/dist/crypto/classical.d.ts +2 -0
- package/dist/crypto/classical.js +4 -0
- package/dist/crypto/classical.js.map +1 -1
- package/dist/crypto/confirmedSession.d.ts +47 -0
- package/dist/crypto/confirmedSession.js +84 -0
- package/dist/crypto/confirmedSession.js.map +1 -0
- package/dist/crypto/frameCipher.js +8 -2
- package/dist/crypto/frameCipher.js.map +1 -1
- package/dist/crypto/frameSession.d.ts +40 -0
- package/dist/crypto/frameSession.js +96 -0
- package/dist/crypto/frameSession.js.map +1 -0
- package/dist/crypto/hybrid.d.ts +95 -8
- package/dist/crypto/hybrid.js +374 -49
- package/dist/crypto/hybrid.js.map +1 -1
- package/dist/crypto/nodeHybrid.d.ts +6 -4
- package/dist/crypto/nodeHybrid.js +3 -2
- package/dist/crypto/nodeHybrid.js.map +1 -1
- package/dist/crypto/pqc.d.ts +7 -2
- package/dist/crypto/pqc.js +13 -4
- package/dist/crypto/pqc.js.map +1 -1
- package/dist/crypto/ratchet.js +5 -0
- package/dist/crypto/ratchet.js.map +1 -1
- package/dist/fileCrypto.d.ts +44 -2
- package/dist/fileCrypto.js +198 -28
- package/dist/fileCrypto.js.map +1 -1
- package/dist/identity.d.ts +69 -4
- package/dist/identity.js +148 -13
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/passphrase.d.ts +27 -0
- package/dist/passphrase.js +69 -0
- package/dist/passphrase.js.map +1 -0
- package/dist/store.d.ts +43 -6
- package/dist/store.js +296 -23
- package/dist/store.js.map +1 -1
- package/dist/trust.d.ts +170 -2
- package/dist/trust.js +527 -33
- package/dist/trust.js.map +1 -1
- package/package.json +68 -69
package/dist/crypto/hybrid.d.ts
CHANGED
|
@@ -7,6 +7,23 @@ 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;
|
|
10
27
|
export interface Certificate {
|
|
11
28
|
documentHash: string;
|
|
12
29
|
classicalSignature: string;
|
|
@@ -18,6 +35,14 @@ export interface Certificate {
|
|
|
18
35
|
pqcSignPublicKey: string;
|
|
19
36
|
};
|
|
20
37
|
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;
|
|
21
46
|
/** Absent = permanent proof, valid indefinitely (the default, unchanged behavior). */
|
|
22
47
|
expiresAt?: string;
|
|
23
48
|
}
|
|
@@ -25,7 +50,7 @@ export interface SignOptions {
|
|
|
25
50
|
/** If set, verify() rejects this certificate as "expired" once this ISO timestamp has passed. */
|
|
26
51
|
expiresAt?: string;
|
|
27
52
|
}
|
|
28
|
-
export type VerifyFailureReason = "untrusted-signer" | "revoked-signer" | "hash-mismatch" | "classical-signature-mismatch" | "pqc-signature-mismatch" | "expired";
|
|
53
|
+
export type VerifyFailureReason = "untrusted-signer" | "revoked-signer" | "hash-mismatch" | "classical-signature-mismatch" | "pqc-signature-mismatch" | "expired" | "malformed-certificate" | "fingerprint-mismatch";
|
|
29
54
|
export type VerifyResult = {
|
|
30
55
|
valid: true;
|
|
31
56
|
} | {
|
|
@@ -68,24 +93,57 @@ export declare function signCore(identity: Identity, document: unknown, options?
|
|
|
68
93
|
*/
|
|
69
94
|
export declare function verifyCore(identity: Identity, document: unknown, certificate: Certificate, deps: VerifyDeps): Promise<VerifyResult>;
|
|
70
95
|
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;
|
|
71
102
|
kemCipherText: string;
|
|
72
103
|
nonce: string;
|
|
73
104
|
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>;
|
|
74
124
|
}
|
|
75
125
|
/**
|
|
76
|
-
* Encrypts `data` for `counterpart`
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
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.
|
|
80
135
|
*/
|
|
81
136
|
export declare function encryptForCore(identity: Identity, counterpart: PublicCard, data: unknown, deps: TrustDeps): Promise<EncryptedBox>;
|
|
82
137
|
/**
|
|
83
138
|
* Decrypts a box produced by `encryptFor`. `counterpart` is the sender's
|
|
84
139
|
* public card. Throws UntrustedPartyError unless `deps.checkTrust(counterpart)`
|
|
85
|
-
* reports "trusted"
|
|
86
|
-
*
|
|
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.
|
|
87
145
|
*/
|
|
88
|
-
export declare function decryptFromCore<T = unknown>(identity: Identity, counterpart: PublicCard, box: EncryptedBox, deps:
|
|
146
|
+
export declare function decryptFromCore<T = unknown>(identity: Identity, counterpart: PublicCard, box: EncryptedBox, deps: DecryptDeps): Promise<T>;
|
|
89
147
|
export interface SessionKeys {
|
|
90
148
|
/** AES-256-GCM key for frames sent by the initiator, decrypted by the responder. */
|
|
91
149
|
initiatorToResponder: Uint8Array;
|
|
@@ -154,6 +212,35 @@ export interface ResponderSessionResult {
|
|
|
154
212
|
export declare class HandshakeVerificationError extends Error {
|
|
155
213
|
constructor(message: string);
|
|
156
214
|
}
|
|
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;
|
|
157
244
|
/**
|
|
158
245
|
* First step of the handshake, run by the connection's responder: generates
|
|
159
246
|
* one fresh, single-use ECDH-P384 keypair and one fresh, single-use
|