raz-encrypt 0.1.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 -0
- package/README.md +225 -0
- package/dist/canonicalJson.d.ts +3 -0
- package/dist/canonicalJson.js +25 -0
- package/dist/canonicalJson.js.map +1 -0
- package/dist/core.d.ts +23 -0
- package/dist/core.js +19 -0
- package/dist/core.js.map +1 -0
- package/dist/crypto/classical.d.ts +10 -0
- package/dist/crypto/classical.js +21 -0
- package/dist/crypto/classical.js.map +1 -0
- package/dist/crypto/frameCipher.d.ts +23 -0
- package/dist/crypto/frameCipher.js +58 -0
- package/dist/crypto/frameCipher.js.map +1 -0
- package/dist/crypto/hybrid.d.ts +117 -0
- package/dist/crypto/hybrid.js +180 -0
- package/dist/crypto/hybrid.js.map +1 -0
- package/dist/crypto/nodeHybrid.d.ts +42 -0
- package/dist/crypto/nodeHybrid.js +65 -0
- package/dist/crypto/nodeHybrid.js.map +1 -0
- package/dist/crypto/pqc.d.ts +19 -0
- package/dist/crypto/pqc.js +28 -0
- package/dist/crypto/pqc.js.map +1 -0
- package/dist/fileCrypto.d.ts +6 -0
- package/dist/fileCrypto.js +45 -0
- package/dist/fileCrypto.js.map +1 -0
- package/dist/fingerprint.d.ts +11 -0
- package/dist/fingerprint.js +18 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/identity.d.ts +42 -0
- package/dist/identity.js +87 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/store.d.ts +28 -0
- package/dist/store.js +62 -0
- package/dist/store.js.map +1 -0
- package/dist/trust.d.ts +41 -0
- package/dist/trust.js +98 -0
- package/dist/trust.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { gcm } from "@noble/ciphers/aes.js";
|
|
2
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
3
|
+
import { sha384 } from "@noble/hashes/sha2.js";
|
|
4
|
+
import { bytesToHex, concatBytes, hexToBytes, randomBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
5
|
+
import { canonicalize, hashDocument } from "../canonicalJson.js";
|
|
6
|
+
import { classicalSharedSecret, classicalSign, classicalVerify } from "./classical.js";
|
|
7
|
+
import { pqcDecapsulate, pqcEncapsulate, pqcSign, pqcVerify } from "./pqc.js";
|
|
8
|
+
// No import of ../store.js or ../trust.js here (only their LogEntry TYPE,
|
|
9
|
+
// which is erased at compile time) — this file must stay resolvable by a
|
|
10
|
+
// browser bundler on its own. The node:fs-backed default wiring for
|
|
11
|
+
// sign/verify/encryptFor/decryptFrom lives in ./nodeHybrid.ts instead,
|
|
12
|
+
// which is what "." (not "./core") re-exports.
|
|
13
|
+
const HYBRID_INFO = utf8ToBytes("raz-encrypt-hybrid-v1");
|
|
14
|
+
const ALGORITHMS = { classical: "ECDSA-P384", pqc: "ML-DSA-87" };
|
|
15
|
+
export class UntrustedPartyError extends Error {
|
|
16
|
+
constructor(alias) {
|
|
17
|
+
super(`"${alias}" is not in the local trust list. Call trustParty() with their public card first.`);
|
|
18
|
+
this.name = "UntrustedPartyError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The exact bytes both signatures are computed over. Binds `expiresAt` into
|
|
23
|
+
* the signed payload (not just `documentHash`) so a certificate's expiry
|
|
24
|
+
* can't be stripped or altered in transit without invalidating both
|
|
25
|
+
* signatures — an untrusted intermediary who only has the certificate
|
|
26
|
+
* (no secret key) must not be able to turn an expired certificate back into
|
|
27
|
+
* one that verify() accepts.
|
|
28
|
+
*/
|
|
29
|
+
function signedMessage(documentHash, expiresAt) {
|
|
30
|
+
return utf8ToBytes(canonicalize({ documentHash, expiresAt: expiresAt ?? null }));
|
|
31
|
+
}
|
|
32
|
+
async function requireTrusted(checkTrust, counterpart) {
|
|
33
|
+
const status = await checkTrust(counterpart);
|
|
34
|
+
if (status !== "trusted")
|
|
35
|
+
throw new UntrustedPartyError(counterpart.alias);
|
|
36
|
+
}
|
|
37
|
+
async function log(onLog, entry) {
|
|
38
|
+
if (onLog)
|
|
39
|
+
await onLog(entry);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Signs `document` with both the classical (ECDSA-P384) and post-quantum
|
|
43
|
+
* (ML-DSA-87) keys. Permanent by default; pass `options.expiresAt` to make
|
|
44
|
+
* verify() reject it once that time has passed. Takes no trust dependency —
|
|
45
|
+
* signing never checks anyone else's trust status, only your own keys.
|
|
46
|
+
*/
|
|
47
|
+
export async function signCore(identity, document, options = {}, deps = {}) {
|
|
48
|
+
const documentHash = hashDocument(document);
|
|
49
|
+
const message = signedMessage(documentHash, options.expiresAt);
|
|
50
|
+
const certificate = {
|
|
51
|
+
documentHash,
|
|
52
|
+
classicalSignature: bytesToHex(classicalSign(message, identity.classical.secretKey)),
|
|
53
|
+
pqcSignature: bytesToHex(pqcSign(message, identity.pqcSign.secretKey)),
|
|
54
|
+
algorithms: ALGORITHMS,
|
|
55
|
+
signer: {
|
|
56
|
+
alias: identity.alias,
|
|
57
|
+
classicalPublicKey: bytesToHex(identity.classical.publicKey),
|
|
58
|
+
pqcSignPublicKey: bytesToHex(identity.pqcSign.publicKey),
|
|
59
|
+
},
|
|
60
|
+
signedAt: new Date().toISOString(),
|
|
61
|
+
...(options.expiresAt ? { expiresAt: options.expiresAt } : {}),
|
|
62
|
+
};
|
|
63
|
+
await log(deps.onLog, { action: "sign", documentHash });
|
|
64
|
+
return certificate;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Verifies `certificate` over `document` using an injected trust check
|
|
68
|
+
* (`deps.checkTrust`) instead of a hard-wired trust store. Requires BOTH the
|
|
69
|
+
* classical and post-quantum signatures to check out — either one failing
|
|
70
|
+
* fails the whole verification.
|
|
71
|
+
*/
|
|
72
|
+
export async function verifyCore(identity, document, certificate, deps) {
|
|
73
|
+
const record = (result) => {
|
|
74
|
+
void log(deps.onLog, {
|
|
75
|
+
action: "verify",
|
|
76
|
+
documentHash: certificate.documentHash,
|
|
77
|
+
counterpartAlias: certificate.signer.alias,
|
|
78
|
+
result: result.valid ? "valid" : result.reason,
|
|
79
|
+
});
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
const status = await deps.checkTrust(certificate.signer);
|
|
83
|
+
if (status === "untrusted") {
|
|
84
|
+
return record({ valid: false, reason: "untrusted-signer" });
|
|
85
|
+
}
|
|
86
|
+
if (status === "revoked") {
|
|
87
|
+
return record({ valid: false, reason: "revoked-signer" });
|
|
88
|
+
}
|
|
89
|
+
if (hashDocument(document) !== certificate.documentHash) {
|
|
90
|
+
return record({ valid: false, reason: "hash-mismatch" });
|
|
91
|
+
}
|
|
92
|
+
if (certificate.expiresAt && Date.now() >= Date.parse(certificate.expiresAt)) {
|
|
93
|
+
return record({ valid: false, reason: "expired" });
|
|
94
|
+
}
|
|
95
|
+
const message = signedMessage(certificate.documentHash, certificate.expiresAt);
|
|
96
|
+
const classicalOk = classicalVerify(hexToBytes(certificate.classicalSignature), message, hexToBytes(certificate.signer.classicalPublicKey));
|
|
97
|
+
if (!classicalOk)
|
|
98
|
+
return record({ valid: false, reason: "classical-signature-mismatch" });
|
|
99
|
+
const pqcOk = pqcVerify(hexToBytes(certificate.pqcSignature), message, hexToBytes(certificate.signer.pqcSignPublicKey));
|
|
100
|
+
if (!pqcOk)
|
|
101
|
+
return record({ valid: false, reason: "pqc-signature-mismatch" });
|
|
102
|
+
return record({ valid: true });
|
|
103
|
+
}
|
|
104
|
+
function deriveHybridKey(ecdhSecret, kemSecret) {
|
|
105
|
+
return hkdf(sha384, concatBytes(ecdhSecret, kemSecret), undefined, HYBRID_INFO, 32);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Encrypts `data` for `counterpart` using a symmetric key derived from BOTH
|
|
109
|
+
* an ECDH-P384 exchange and an ML-KEM-1024 encapsulation (HKDF-SHA384
|
|
110
|
+
* combines the two secrets), then AES-256-GCM. Throws UntrustedPartyError
|
|
111
|
+
* unless `deps.checkTrust(counterpart)` reports "trusted".
|
|
112
|
+
*/
|
|
113
|
+
export async function encryptForCore(identity, counterpart, data, deps) {
|
|
114
|
+
await requireTrusted(deps.checkTrust, counterpart);
|
|
115
|
+
const ecdhSecret = classicalSharedSecret(identity.classical.secretKey, hexToBytes(counterpart.classicalPublicKey));
|
|
116
|
+
const { cipherText: kemCipherText, sharedSecret: kemSecret } = pqcEncapsulate(hexToBytes(counterpart.pqcKemPublicKey));
|
|
117
|
+
const key = deriveHybridKey(ecdhSecret, kemSecret);
|
|
118
|
+
const nonce = randomBytes(12);
|
|
119
|
+
const ciphertext = gcm(key, nonce).encrypt(utf8ToBytes(canonicalize(data)));
|
|
120
|
+
await log(deps.onLog, { action: "encrypt", counterpartAlias: counterpart.alias });
|
|
121
|
+
return { kemCipherText: bytesToHex(kemCipherText), nonce: bytesToHex(nonce), ciphertext: bytesToHex(ciphertext) };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Decrypts a box produced by `encryptFor`. `counterpart` is the sender's
|
|
125
|
+
* public card. Throws UntrustedPartyError unless `deps.checkTrust(counterpart)`
|
|
126
|
+
* reports "trusted" — this stops a caller from accidentally decrypting "as
|
|
127
|
+
* if" a message came from someone they never actually trusted.
|
|
128
|
+
*/
|
|
129
|
+
export async function decryptFromCore(identity, counterpart, box, deps) {
|
|
130
|
+
await requireTrusted(deps.checkTrust, counterpart);
|
|
131
|
+
const ecdhSecret = classicalSharedSecret(identity.classical.secretKey, hexToBytes(counterpart.classicalPublicKey));
|
|
132
|
+
const kemSecret = pqcDecapsulate(hexToBytes(box.kemCipherText), identity.pqcKem.secretKey);
|
|
133
|
+
const key = deriveHybridKey(ecdhSecret, kemSecret);
|
|
134
|
+
const plaintext = gcm(key, hexToBytes(box.nonce)).decrypt(hexToBytes(box.ciphertext));
|
|
135
|
+
await log(deps.onLog, { action: "decrypt", counterpartAlias: counterpart.alias });
|
|
136
|
+
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
137
|
+
}
|
|
138
|
+
// --- Session handshake ------------------------------------------------
|
|
139
|
+
//
|
|
140
|
+
// encryptForCore/decryptFromCore above do a full ECDH + ML-KEM encapsulation
|
|
141
|
+
// PER CALL — fine for a one-off document, prohibitively expensive if called
|
|
142
|
+
// once per 16 KiB chunk of a large file transfer. The functions below run
|
|
143
|
+
// that hybrid exchange ONCE per connection and hand back a pair of
|
|
144
|
+
// directional keys the caller reuses (via a separate per-frame cipher, not
|
|
145
|
+
// implemented here) for as many messages as the connection carries.
|
|
146
|
+
const SESSION_INFO_INITIATOR_TO_RESPONDER = utf8ToBytes("raz-encrypt-session-v1|initiator-to-responder");
|
|
147
|
+
const SESSION_INFO_RESPONDER_TO_INITIATOR = utf8ToBytes("raz-encrypt-session-v1|responder-to-initiator");
|
|
148
|
+
function deriveSessionKeys(ecdhSecret, kemSecret) {
|
|
149
|
+
const ikm = concatBytes(ecdhSecret, kemSecret);
|
|
150
|
+
return {
|
|
151
|
+
initiatorToResponder: hkdf(sha384, ikm, undefined, SESSION_INFO_INITIATOR_TO_RESPONDER, 32),
|
|
152
|
+
responderToInitiator: hkdf(sha384, ikm, undefined, SESSION_INFO_RESPONDER_TO_INITIATOR, 32),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Establishes a session as the connection's initiator (the side that
|
|
157
|
+
* created the WebRTC offer, in raz-encrypt-agnostic terms: whichever side
|
|
158
|
+
* owns the single ML-KEM encapsulation this handshake performs). Computes
|
|
159
|
+
* the ECDH-P384 secret with `counterpart` and one ML-KEM-1024 encapsulation
|
|
160
|
+
* toward their KEM public key, then HKDF-splits the combined secret into two
|
|
161
|
+
* directional AES-256-GCM keys. No trust dependency: establishing a session
|
|
162
|
+
* never checks anyone's trust status, same as signCore.
|
|
163
|
+
*/
|
|
164
|
+
export function establishSessionInitiatorCore(identity, counterpart) {
|
|
165
|
+
const ecdhSecret = classicalSharedSecret(identity.classical.secretKey, hexToBytes(counterpart.classicalPublicKey));
|
|
166
|
+
const { cipherText, sharedSecret: kemSecret } = pqcEncapsulate(hexToBytes(counterpart.pqcKemPublicKey));
|
|
167
|
+
return { kemCipherText: bytesToHex(cipherText), keys: deriveSessionKeys(ecdhSecret, kemSecret) };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Establishes a session as the connection's responder: computes the same
|
|
171
|
+
* ECDH-P384 secret, decapsulates the initiator's `kemCipherText` with our
|
|
172
|
+
* own KEM secret key, and derives the same two directional keys the
|
|
173
|
+
* initiator derived.
|
|
174
|
+
*/
|
|
175
|
+
export function establishSessionResponderCore(identity, counterpart, kemCipherText) {
|
|
176
|
+
const ecdhSecret = classicalSharedSecret(identity.classical.secretKey, hexToBytes(counterpart.classicalPublicKey));
|
|
177
|
+
const kemSecret = pqcDecapsulate(hexToBytes(kemCipherText), identity.pqcKem.secretKey);
|
|
178
|
+
return deriveSessionKeys(ecdhSecret, kemSecret);
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=hybrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid.js","sourceRoot":"","sources":["../../src/crypto/hybrid.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default (Node, fs-backed) wiring for the "." package export — the
|
|
3
|
+
* library's original public API. Behavior is unchanged from before the
|
|
4
|
+
* injectable-trust/log refactor: these still check identity's persisted
|
|
5
|
+
* trust store and append to its persisted audit log.
|
|
6
|
+
*
|
|
7
|
+
* This file is deliberately separate from ./hybrid.ts: it's the only place
|
|
8
|
+
* that imports ../trust.js and ../store.js (both node:fs-backed), so
|
|
9
|
+
* ./hybrid.ts — and therefore the "./core" export built from it — stays
|
|
10
|
+
* resolvable by a browser bundler with no node:fs in its module graph.
|
|
11
|
+
*/
|
|
12
|
+
import type { Identity, PublicCard } from "../identity.js";
|
|
13
|
+
import { type Certificate, type EncryptedBox, type SignOptions, type VerifyResult } from "./hybrid.js";
|
|
14
|
+
export { UntrustedPartyError } from "./hybrid.js";
|
|
15
|
+
export type { Certificate, EncryptedBox, SignOptions, VerifyFailureReason, VerifyResult } from "./hybrid.js";
|
|
16
|
+
/**
|
|
17
|
+
* Signs `document` with both the classical (ECDSA-P384) and post-quantum
|
|
18
|
+
* (ML-DSA-87) keys. Permanent by default; pass `options.expiresAt` to make
|
|
19
|
+
* verify() reject it once that time has passed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sign(identity: Identity, document: unknown, options?: SignOptions): Promise<Certificate>;
|
|
22
|
+
/**
|
|
23
|
+
* Verifies `certificate` over `document`. Requires the signer to already be
|
|
24
|
+
* in `identity`'s local trust list (see trustParty), and requires BOTH the
|
|
25
|
+
* classical and post-quantum signatures to check out — either one failing
|
|
26
|
+
* fails the whole verification.
|
|
27
|
+
*/
|
|
28
|
+
export declare function verify(identity: Identity, document: unknown, certificate: Certificate): Promise<VerifyResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Encrypts `data` for `counterpart` using a symmetric key derived from BOTH
|
|
31
|
+
* an ECDH-P384 exchange and an ML-KEM-1024 encapsulation (HKDF-SHA384
|
|
32
|
+
* combines the two secrets), then AES-256-GCM. Throws UntrustedPartyError
|
|
33
|
+
* unless `counterpart` is already in `identity`'s local trust list.
|
|
34
|
+
*/
|
|
35
|
+
export declare function encryptFor(identity: Identity, counterpart: PublicCard, data: unknown): Promise<EncryptedBox>;
|
|
36
|
+
/**
|
|
37
|
+
* Decrypts a box produced by `encryptFor`. `counterpart` is the sender's
|
|
38
|
+
* public card. Throws UntrustedPartyError unless `counterpart` is already
|
|
39
|
+
* in `identity`'s local trust list — this stops a caller from accidentally
|
|
40
|
+
* decrypting "as if" a message came from someone they never actually trusted.
|
|
41
|
+
*/
|
|
42
|
+
export declare function decryptFrom<T = unknown>(identity: Identity, counterpart: PublicCard, box: EncryptedBox): Promise<T>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { appendLogEntry } from "../store.js";
|
|
2
|
+
import { getTrustRecordsByAlias, getTrustedPartiesByAlias } from "../trust.js";
|
|
3
|
+
import { decryptFromCore, encryptForCore, signCore, verifyCore, } from "./hybrid.js";
|
|
4
|
+
export { UntrustedPartyError } from "./hybrid.js";
|
|
5
|
+
async function trustStatusForSigner(identity, signer) {
|
|
6
|
+
const allRecords = await getTrustRecordsByAlias(identity, signer.alias);
|
|
7
|
+
const matchingRecord = allRecords.find((r) => r.card.classicalPublicKey === signer.classicalPublicKey && r.card.pqcSignPublicKey === signer.pqcSignPublicKey);
|
|
8
|
+
if (!matchingRecord)
|
|
9
|
+
return "untrusted";
|
|
10
|
+
if (matchingRecord.revokedAt)
|
|
11
|
+
return "revoked";
|
|
12
|
+
return "trusted";
|
|
13
|
+
}
|
|
14
|
+
async function trustStatusForCard(identity, card) {
|
|
15
|
+
const candidates = await getTrustedPartiesByAlias(identity, card.alias);
|
|
16
|
+
const isTrusted = candidates.some((trusted) => trusted.classicalPublicKey === card.classicalPublicKey &&
|
|
17
|
+
trusted.pqcSignPublicKey === card.pqcSignPublicKey &&
|
|
18
|
+
trusted.pqcKemPublicKey === card.pqcKemPublicKey);
|
|
19
|
+
return isTrusted ? "trusted" : "untrusted";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Signs `document` with both the classical (ECDSA-P384) and post-quantum
|
|
23
|
+
* (ML-DSA-87) keys. Permanent by default; pass `options.expiresAt` to make
|
|
24
|
+
* verify() reject it once that time has passed.
|
|
25
|
+
*/
|
|
26
|
+
export async function sign(identity, document, options = {}) {
|
|
27
|
+
return signCore(identity, document, options, { onLog: (entry) => appendLogEntry(identity, entry) });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Verifies `certificate` over `document`. Requires the signer to already be
|
|
31
|
+
* in `identity`'s local trust list (see trustParty), and requires BOTH the
|
|
32
|
+
* classical and post-quantum signatures to check out — either one failing
|
|
33
|
+
* fails the whole verification.
|
|
34
|
+
*/
|
|
35
|
+
export async function verify(identity, document, certificate) {
|
|
36
|
+
return verifyCore(identity, document, certificate, {
|
|
37
|
+
checkTrust: (signer) => trustStatusForSigner(identity, signer),
|
|
38
|
+
onLog: (entry) => appendLogEntry(identity, entry),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Encrypts `data` for `counterpart` using a symmetric key derived from BOTH
|
|
43
|
+
* an ECDH-P384 exchange and an ML-KEM-1024 encapsulation (HKDF-SHA384
|
|
44
|
+
* combines the two secrets), then AES-256-GCM. Throws UntrustedPartyError
|
|
45
|
+
* unless `counterpart` is already in `identity`'s local trust list.
|
|
46
|
+
*/
|
|
47
|
+
export async function encryptFor(identity, counterpart, data) {
|
|
48
|
+
return encryptForCore(identity, counterpart, data, {
|
|
49
|
+
checkTrust: (card) => trustStatusForCard(identity, card),
|
|
50
|
+
onLog: (entry) => appendLogEntry(identity, entry),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Decrypts a box produced by `encryptFor`. `counterpart` is the sender's
|
|
55
|
+
* public card. Throws UntrustedPartyError unless `counterpart` is already
|
|
56
|
+
* in `identity`'s local trust list — this stops a caller from accidentally
|
|
57
|
+
* decrypting "as if" a message came from someone they never actually trusted.
|
|
58
|
+
*/
|
|
59
|
+
export async function decryptFrom(identity, counterpart, box) {
|
|
60
|
+
return decryptFromCore(identity, counterpart, box, {
|
|
61
|
+
checkTrust: (card) => trustStatusForCard(identity, card),
|
|
62
|
+
onLog: (entry) => appendLogEntry(identity, entry),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=nodeHybrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeHybrid.js","sourceRoot":"","sources":["../../src/crypto/nodeHybrid.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,eAAe,EACf,cAAc,EACd,QAAQ,EAMR,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,KAAK,UAAU,oBAAoB,CACjC,QAAkB,EAClB,MAA+E;IAE/E,MAAM,UAAU,GAAG,MAAM,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,KAAK,MAAM,CAAC,kBAAkB,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,KAAK,MAAM,CAAC,gBAAgB,CACtH,CAAC;IACF,IAAI,CAAC,cAAc;QAAE,OAAO,WAAW,CAAC;IACxC,IAAI,cAAc,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,QAAkB,EAAE,IAAgB;IACpE,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAC/B,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,CAAC,kBAAkB,KAAK,IAAI,CAAC,kBAAkB;QACtD,OAAO,CAAC,gBAAgB,KAAK,IAAI,CAAC,gBAAgB;QAClD,OAAO,CAAC,eAAe,KAAK,IAAI,CAAC,eAAe,CACnD,CAAC;IACF,OAAO,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,QAAkB,EAAE,QAAiB,EAAE,UAAuB,EAAE;IACzF,OAAO,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAkB,EAAE,QAAiB,EAAE,WAAwB;IAC1F,OAAO,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE;QACjD,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC9D,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC;KAClD,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAkB,EAAE,WAAuB,EAAE,IAAa;IACzF,OAAO,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE;QACjD,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC;QACxD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC;KAClD,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAc,QAAkB,EAAE,WAAuB,EAAE,GAAiB;IAC3G,OAAO,eAAe,CAAI,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE;QACpD,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC;QACxD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC;KAClD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface PqcSignKeypair {
|
|
2
|
+
publicKey: Uint8Array;
|
|
3
|
+
secretKey: Uint8Array;
|
|
4
|
+
}
|
|
5
|
+
export interface PqcKemKeypair {
|
|
6
|
+
publicKey: Uint8Array;
|
|
7
|
+
secretKey: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
/** ML-DSA-87 (FIPS 204, category-5 parameter set) — the post-quantum signing layer. */
|
|
10
|
+
export declare function generatePqcSignKeypair(): PqcSignKeypair;
|
|
11
|
+
export declare function pqcSign(message: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
|
12
|
+
export declare function pqcVerify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
|
|
13
|
+
/** ML-KEM-1024 (FIPS 203, category-5 parameter set) — the post-quantum key-exchange layer. */
|
|
14
|
+
export declare function generatePqcKemKeypair(): PqcKemKeypair;
|
|
15
|
+
export declare function pqcEncapsulate(theirPublicKey: Uint8Array): {
|
|
16
|
+
cipherText: Uint8Array;
|
|
17
|
+
sharedSecret: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
export declare function pqcDecapsulate(cipherText: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ml_dsa87 } from "@noble/post-quantum/ml-dsa.js";
|
|
2
|
+
import { ml_kem1024 } from "@noble/post-quantum/ml-kem.js";
|
|
3
|
+
/** ML-DSA-87 (FIPS 204, category-5 parameter set) — the post-quantum signing layer. */
|
|
4
|
+
export function generatePqcSignKeypair() {
|
|
5
|
+
return ml_dsa87.keygen();
|
|
6
|
+
}
|
|
7
|
+
export function pqcSign(message, secretKey) {
|
|
8
|
+
return ml_dsa87.sign(message, secretKey);
|
|
9
|
+
}
|
|
10
|
+
export function pqcVerify(signature, message, publicKey) {
|
|
11
|
+
try {
|
|
12
|
+
return ml_dsa87.verify(signature, message, publicKey);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** ML-KEM-1024 (FIPS 203, category-5 parameter set) — the post-quantum key-exchange layer. */
|
|
19
|
+
export function generatePqcKemKeypair() {
|
|
20
|
+
return ml_kem1024.keygen();
|
|
21
|
+
}
|
|
22
|
+
export function pqcEncapsulate(theirPublicKey) {
|
|
23
|
+
return ml_kem1024.encapsulate(theirPublicKey);
|
|
24
|
+
}
|
|
25
|
+
export function pqcDecapsulate(cipherText, secretKey) {
|
|
26
|
+
return ml_kem1024.decapsulate(cipherText, secretKey);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=pqc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pqc.js","sourceRoot":"","sources":["../../src/crypto/pqc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAY3D,uFAAuF;AACvF,MAAM,UAAU,sBAAsB;IACpC,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAmB,EAAE,SAAqB;IAChE,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,SAAqB,EAAE,OAAmB,EAAE,SAAqB;IACzF,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,qBAAqB;IACnC,OAAO,UAAU,CAAC,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,cAA0B;IACvD,OAAO,UAAU,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAsB,EAAE,SAAqB;IAC1E,OAAO,UAAU,CAAC,WAAW,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Encrypts `data` (any JSON-serializable value) at rest under a passphrase-derived AES-256-GCM key. */
|
|
2
|
+
export declare function encryptToFile(filePath: string, passphrase: string, data: unknown): Promise<void>;
|
|
3
|
+
export declare class DecryptionFailedError extends Error {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
export declare function decryptFromFile<T>(filePath: string, passphrase: string): Promise<T>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { gcm } from "@noble/ciphers/aes.js";
|
|
2
|
+
import { scrypt } from "@noble/hashes/scrypt.js";
|
|
3
|
+
import { bytesToHex, hexToBytes, randomBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
4
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
const SCRYPT_PARAMS = { N: 2 ** 17, r: 8, p: 1, dkLen: 32 };
|
|
7
|
+
function deriveKey(passphrase, salt) {
|
|
8
|
+
return scrypt(utf8ToBytes(passphrase), salt, SCRYPT_PARAMS);
|
|
9
|
+
}
|
|
10
|
+
/** Encrypts `data` (any JSON-serializable value) at rest under a passphrase-derived AES-256-GCM key. */
|
|
11
|
+
export async function encryptToFile(filePath, passphrase, data) {
|
|
12
|
+
const salt = randomBytes(16);
|
|
13
|
+
const nonce = randomBytes(12);
|
|
14
|
+
const key = deriveKey(passphrase, salt);
|
|
15
|
+
const plaintext = utf8ToBytes(JSON.stringify(data));
|
|
16
|
+
const ciphertext = gcm(key, nonce).encrypt(plaintext);
|
|
17
|
+
const payload = {
|
|
18
|
+
salt: bytesToHex(salt),
|
|
19
|
+
nonce: bytesToHex(nonce),
|
|
20
|
+
ciphertext: bytesToHex(ciphertext),
|
|
21
|
+
};
|
|
22
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
23
|
+
await writeFile(filePath, JSON.stringify(payload), { mode: 0o600 });
|
|
24
|
+
}
|
|
25
|
+
export class DecryptionFailedError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super("Failed to decrypt local store: wrong passphrase or corrupted/tampered file.");
|
|
28
|
+
this.name = "DecryptionFailedError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function decryptFromFile(filePath, passphrase) {
|
|
32
|
+
const raw = await readFile(filePath, "utf8");
|
|
33
|
+
const payload = JSON.parse(raw);
|
|
34
|
+
const salt = hexToBytes(payload.salt);
|
|
35
|
+
const nonce = hexToBytes(payload.nonce);
|
|
36
|
+
const key = deriveKey(passphrase, salt);
|
|
37
|
+
try {
|
|
38
|
+
const plaintext = gcm(key, nonce).decrypt(hexToBytes(payload.ciphertext));
|
|
39
|
+
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new DecryptionFailedError();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=fileCrypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileCrypto.js","sourceRoot":"","sources":["../src/fileCrypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAQ5D,SAAS,SAAS,CAAC,UAAkB,EAAE,IAAgB;IACrD,OAAO,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;AAC9D,CAAC;AAED,wGAAwG;AACxG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,UAAkB,EAAE,IAAa;IACrF,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAkB;QAC7B,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC;QACtB,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC;QACxB,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC;KACnC,CAAC;IAEF,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C;QACE,KAAK,CAAC,6EAA6E,CAAC,CAAC;QACrF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAI,QAAgB,EAAE,UAAkB;IAC3E,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAM,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,qBAAqB,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PublicCard } from "./identity.js";
|
|
2
|
+
/**
|
|
3
|
+
* A short, human-comparable fingerprint of a PublicCard (PGP/Signal
|
|
4
|
+
* "safety number" style: grouped hex). Two parties should read this aloud
|
|
5
|
+
* or compare it over a side channel (phone call, in person) BEFORE calling
|
|
6
|
+
* trustParty() with a card they received over an unauthenticated channel
|
|
7
|
+
* (email, chat) — this is what catches a spoofed or intercepted card.
|
|
8
|
+
*
|
|
9
|
+
* Does not change trustParty() itself; this is an additive, optional check.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fingerprint(card: PublicCard): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { sha384 } from "@noble/hashes/sha2.js";
|
|
2
|
+
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
3
|
+
import { canonicalize } from "./canonicalJson.js";
|
|
4
|
+
/**
|
|
5
|
+
* A short, human-comparable fingerprint of a PublicCard (PGP/Signal
|
|
6
|
+
* "safety number" style: grouped hex). Two parties should read this aloud
|
|
7
|
+
* or compare it over a side channel (phone call, in person) BEFORE calling
|
|
8
|
+
* trustParty() with a card they received over an unauthenticated channel
|
|
9
|
+
* (email, chat) — this is what catches a spoofed or intercepted card.
|
|
10
|
+
*
|
|
11
|
+
* Does not change trustParty() itself; this is an additive, optional check.
|
|
12
|
+
*/
|
|
13
|
+
export function fingerprint(card) {
|
|
14
|
+
const hash = sha384(utf8ToBytes(canonicalize(card)));
|
|
15
|
+
const hex = bytesToHex(hash.slice(0, 20)).toUpperCase();
|
|
16
|
+
return hex.match(/.{1,4}/g).join(" ");
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACxD,OAAO,GAAG,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ClassicalKeypair } from "./crypto/classical.js";
|
|
2
|
+
import { type PqcKemKeypair, type PqcSignKeypair } from "./crypto/pqc.js";
|
|
3
|
+
export interface Identity {
|
|
4
|
+
alias: string;
|
|
5
|
+
storageDir: string;
|
|
6
|
+
classical: ClassicalKeypair;
|
|
7
|
+
pqcSign: PqcSignKeypair;
|
|
8
|
+
pqcKem: PqcKemKeypair;
|
|
9
|
+
}
|
|
10
|
+
/** The public half of an Identity — safe to hand to the other party. */
|
|
11
|
+
export interface PublicCard {
|
|
12
|
+
alias: string;
|
|
13
|
+
classicalPublicKey: string;
|
|
14
|
+
pqcSignPublicKey: string;
|
|
15
|
+
pqcKemPublicKey: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const MIN_PASSPHRASE_LENGTH = 12;
|
|
18
|
+
export interface CreateIdentityOptions {
|
|
19
|
+
storageDir: string;
|
|
20
|
+
passphrase: string;
|
|
21
|
+
alias: string;
|
|
22
|
+
/** Overwrite an existing identity at this storageDir. Defaults to false. */
|
|
23
|
+
overwrite?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generates a new hybrid classical+post-quantum identity (one ECDSA/ECDH-P384
|
|
27
|
+
* keypair, one ML-DSA-87 signing keypair, one ML-KEM-1024 key-exchange
|
|
28
|
+
* keypair) and persists it encrypted-at-rest under `storageDir`.
|
|
29
|
+
*
|
|
30
|
+
* Requires a passphrase of at least MIN_PASSPHRASE_LENGTH characters — this
|
|
31
|
+
* check only applies here, not to loadIdentity, so an identity created
|
|
32
|
+
* before this check existed can still be loaded with its original passphrase.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createIdentity(options: CreateIdentityOptions): Promise<Identity>;
|
|
35
|
+
export interface LoadIdentityOptions {
|
|
36
|
+
storageDir: string;
|
|
37
|
+
passphrase: string;
|
|
38
|
+
}
|
|
39
|
+
/** Loads a previously-created identity back from disk. */
|
|
40
|
+
export declare function loadIdentity(options: LoadIdentityOptions): Promise<Identity>;
|
|
41
|
+
/** The shareable public half of an identity — hand this to the other party out of band. */
|
|
42
|
+
export declare function exportPublicIdentity(identity: Identity): PublicCard;
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { generateClassicalKeypair } from "./crypto/classical.js";
|
|
5
|
+
import { decryptFromFile, encryptToFile } from "./fileCrypto.js";
|
|
6
|
+
import { generatePqcKemKeypair, generatePqcSignKeypair } from "./crypto/pqc.js";
|
|
7
|
+
function identityFilePath(storageDir) {
|
|
8
|
+
return join(storageDir, "identity.enc.json");
|
|
9
|
+
}
|
|
10
|
+
function serialize(identity) {
|
|
11
|
+
return {
|
|
12
|
+
alias: identity.alias,
|
|
13
|
+
classical: {
|
|
14
|
+
publicKey: bytesToHex(identity.classical.publicKey),
|
|
15
|
+
secretKey: bytesToHex(identity.classical.secretKey),
|
|
16
|
+
},
|
|
17
|
+
pqcSign: {
|
|
18
|
+
publicKey: bytesToHex(identity.pqcSign.publicKey),
|
|
19
|
+
secretKey: bytesToHex(identity.pqcSign.secretKey),
|
|
20
|
+
},
|
|
21
|
+
pqcKem: {
|
|
22
|
+
publicKey: bytesToHex(identity.pqcKem.publicKey),
|
|
23
|
+
secretKey: bytesToHex(identity.pqcKem.secretKey),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function deserialize(storageDir, data) {
|
|
28
|
+
return {
|
|
29
|
+
alias: data.alias,
|
|
30
|
+
storageDir,
|
|
31
|
+
classical: {
|
|
32
|
+
publicKey: hexToBytes(data.classical.publicKey),
|
|
33
|
+
secretKey: hexToBytes(data.classical.secretKey),
|
|
34
|
+
},
|
|
35
|
+
pqcSign: {
|
|
36
|
+
publicKey: hexToBytes(data.pqcSign.publicKey),
|
|
37
|
+
secretKey: hexToBytes(data.pqcSign.secretKey),
|
|
38
|
+
},
|
|
39
|
+
pqcKem: {
|
|
40
|
+
publicKey: hexToBytes(data.pqcKem.publicKey),
|
|
41
|
+
secretKey: hexToBytes(data.pqcKem.secretKey),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export const MIN_PASSPHRASE_LENGTH = 12;
|
|
46
|
+
/**
|
|
47
|
+
* Generates a new hybrid classical+post-quantum identity (one ECDSA/ECDH-P384
|
|
48
|
+
* keypair, one ML-DSA-87 signing keypair, one ML-KEM-1024 key-exchange
|
|
49
|
+
* keypair) and persists it encrypted-at-rest under `storageDir`.
|
|
50
|
+
*
|
|
51
|
+
* Requires a passphrase of at least MIN_PASSPHRASE_LENGTH characters — this
|
|
52
|
+
* check only applies here, not to loadIdentity, so an identity created
|
|
53
|
+
* before this check existed can still be loaded with its original passphrase.
|
|
54
|
+
*/
|
|
55
|
+
export async function createIdentity(options) {
|
|
56
|
+
if (options.passphrase.length < MIN_PASSPHRASE_LENGTH) {
|
|
57
|
+
throw new Error(`Passphrase must be at least ${MIN_PASSPHRASE_LENGTH} characters long.`);
|
|
58
|
+
}
|
|
59
|
+
const filePath = identityFilePath(options.storageDir);
|
|
60
|
+
if (!options.overwrite && existsSync(filePath)) {
|
|
61
|
+
throw new Error(`An identity already exists at ${filePath}. Pass { overwrite: true } to replace it.`);
|
|
62
|
+
}
|
|
63
|
+
const identity = {
|
|
64
|
+
alias: options.alias,
|
|
65
|
+
storageDir: options.storageDir,
|
|
66
|
+
classical: generateClassicalKeypair(),
|
|
67
|
+
pqcSign: generatePqcSignKeypair(),
|
|
68
|
+
pqcKem: generatePqcKemKeypair(),
|
|
69
|
+
};
|
|
70
|
+
await encryptToFile(filePath, options.passphrase, serialize(identity));
|
|
71
|
+
return identity;
|
|
72
|
+
}
|
|
73
|
+
/** Loads a previously-created identity back from disk. */
|
|
74
|
+
export async function loadIdentity(options) {
|
|
75
|
+
const data = await decryptFromFile(identityFilePath(options.storageDir), options.passphrase);
|
|
76
|
+
return deserialize(options.storageDir, data);
|
|
77
|
+
}
|
|
78
|
+
/** The shareable public half of an identity — hand this to the other party out of band. */
|
|
79
|
+
export function exportPublicIdentity(identity) {
|
|
80
|
+
return {
|
|
81
|
+
alias: identity.alias,
|
|
82
|
+
classicalPublicKey: bytesToHex(identity.classical.publicKey),
|
|
83
|
+
pqcSignPublicKey: bytesToHex(identity.pqcSign.publicKey),
|
|
84
|
+
pqcKemPublicKey: bytesToHex(identity.pqcKem.publicKey),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { canonicalize, hashDocument } from "./canonicalJson.js";
|
|
2
|
+
export { fingerprint } from "./fingerprint.js";
|
|
3
|
+
export { decryptFrom, encryptFor, sign, UntrustedPartyError, verify } from "./crypto/nodeHybrid.js";
|
|
4
|
+
export type { Certificate, EncryptedBox, VerifyFailureReason, VerifyResult } from "./crypto/nodeHybrid.js";
|
|
5
|
+
export { createIdentity, exportPublicIdentity, loadIdentity, MIN_PASSPHRASE_LENGTH } from "./identity.js";
|
|
6
|
+
export type { CreateIdentityOptions, Identity, LoadIdentityOptions, PublicCard } from "./identity.js";
|
|
7
|
+
export { readLog, verifyLogIntegrity } from "./store.js";
|
|
8
|
+
export type { LogEntry, LogIntegrityResult } from "./store.js";
|
|
9
|
+
export { getTrustedParty, getTrustedPartiesByAlias, getTrustRecordsByAlias, listTrustedParties, listTrustRecords, trustParty, untrustParty, } from "./trust.js";
|
|
10
|
+
export type { TrustRecord } from "./trust.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { canonicalize, hashDocument } from "./canonicalJson.js";
|
|
2
|
+
export { fingerprint } from "./fingerprint.js";
|
|
3
|
+
export { decryptFrom, encryptFor, sign, UntrustedPartyError, verify } from "./crypto/nodeHybrid.js";
|
|
4
|
+
export { createIdentity, exportPublicIdentity, loadIdentity, MIN_PASSPHRASE_LENGTH } from "./identity.js";
|
|
5
|
+
export { readLog, verifyLogIntegrity } from "./store.js";
|
|
6
|
+
export { getTrustedParty, getTrustedPartiesByAlias, getTrustRecordsByAlias, listTrustedParties, listTrustRecords, trustParty, untrustParty, } from "./trust.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEpG,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE1G,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAC"}
|