@psavelis/enterprise-blockchain 0.1.0 → 1.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/dist/aid-settlement/application/reconciler.d.ts +13 -0
- package/dist/aid-settlement/application/reconciler.d.ts.map +1 -0
- package/dist/aid-settlement/application/reconciler.js +77 -0
- package/dist/aid-settlement/domain/entities.d.ts +24 -0
- package/dist/aid-settlement/domain/entities.d.ts.map +1 -0
- package/dist/aid-settlement/domain/entities.js +1 -0
- package/dist/aid-settlement/domain/ports.d.ts +10 -0
- package/dist/aid-settlement/domain/ports.d.ts.map +1 -0
- package/dist/aid-settlement/domain/ports.js +1 -0
- package/dist/aid-settlement/index.d.ts +19 -0
- package/dist/aid-settlement/index.d.ts.map +1 -0
- package/dist/aid-settlement/index.js +23 -0
- package/dist/aid-settlement/infrastructure/in-memory-store.d.ts +12 -0
- package/dist/aid-settlement/infrastructure/in-memory-store.d.ts.map +1 -0
- package/dist/aid-settlement/infrastructure/in-memory-store.js +17 -0
- package/dist/credentialing/application/clearance-evaluator.d.ts +10 -0
- package/dist/credentialing/application/clearance-evaluator.d.ts.map +1 -0
- package/dist/credentialing/application/clearance-evaluator.js +63 -0
- package/dist/credentialing/domain/entities.d.ts +28 -0
- package/dist/credentialing/domain/entities.d.ts.map +1 -0
- package/dist/credentialing/domain/entities.js +1 -0
- package/dist/credentialing/domain/ports.d.ts +9 -0
- package/dist/credentialing/domain/ports.d.ts.map +1 -0
- package/dist/credentialing/domain/ports.js +1 -0
- package/dist/credentialing/index.d.ts +19 -0
- package/dist/credentialing/index.d.ts.map +1 -0
- package/dist/credentialing/index.js +23 -0
- package/dist/credentialing/infrastructure/in-memory-store.d.ts +11 -0
- package/dist/credentialing/infrastructure/in-memory-store.d.ts.map +1 -0
- package/dist/credentialing/infrastructure/in-memory-store.js +14 -0
- package/dist/hsm/application/asymmetric-key-service.d.ts +23 -0
- package/dist/hsm/application/asymmetric-key-service.d.ts.map +1 -0
- package/dist/hsm/application/asymmetric-key-service.js +109 -0
- package/dist/hsm/application/envelope-encryption-service.d.ts +18 -0
- package/dist/hsm/application/envelope-encryption-service.d.ts.map +1 -0
- package/dist/hsm/application/envelope-encryption-service.js +59 -0
- package/dist/hsm/application/symmetric-key-service.d.ts +34 -0
- package/dist/hsm/application/symmetric-key-service.d.ts.map +1 -0
- package/dist/hsm/application/symmetric-key-service.js +107 -0
- package/dist/hsm/domain/entities.d.ts +104 -0
- package/dist/hsm/domain/entities.d.ts.map +1 -0
- package/dist/hsm/domain/entities.js +10 -0
- package/dist/hsm/domain/ports.d.ts +20 -0
- package/dist/hsm/domain/ports.d.ts.map +1 -0
- package/dist/hsm/domain/ports.js +1 -0
- package/dist/hsm/index.d.ts +48 -0
- package/dist/hsm/index.d.ts.map +1 -0
- package/dist/hsm/index.js +97 -0
- package/dist/hsm/infrastructure/audit-log-factory.d.ts +59 -0
- package/dist/hsm/infrastructure/audit-log-factory.d.ts.map +1 -0
- package/dist/hsm/infrastructure/audit-log-factory.js +95 -0
- package/dist/hsm/infrastructure/audit-log.d.ts +8 -0
- package/dist/hsm/infrastructure/audit-log.d.ts.map +1 -0
- package/dist/hsm/infrastructure/audit-log.js +18 -0
- package/dist/hsm/infrastructure/file-audit-log.d.ts +55 -0
- package/dist/hsm/infrastructure/file-audit-log.d.ts.map +1 -0
- package/dist/hsm/infrastructure/file-audit-log.js +128 -0
- package/dist/hsm/infrastructure/key-store.d.ts +9 -0
- package/dist/hsm/infrastructure/key-store.d.ts.map +1 -0
- package/dist/hsm/infrastructure/key-store.js +12 -0
- package/dist/hsm/infrastructure/syslog-audit-log.d.ts +64 -0
- package/dist/hsm/infrastructure/syslog-audit-log.d.ts.map +1 -0
- package/dist/hsm/infrastructure/syslog-audit-log.js +167 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/integrations/besu-client/error-mapper.d.ts +9 -0
- package/dist/integrations/besu-client/error-mapper.d.ts.map +1 -0
- package/dist/integrations/besu-client/error-mapper.js +22 -0
- package/dist/integrations/besu-client/index.d.ts +65 -0
- package/dist/integrations/besu-client/index.d.ts.map +1 -0
- package/dist/integrations/besu-client/index.js +276 -0
- package/dist/integrations/besu-client/ports.d.ts +44 -0
- package/dist/integrations/besu-client/ports.d.ts.map +1 -0
- package/dist/integrations/besu-client/ports.js +1 -0
- package/dist/integrations/corda-gateway/index.d.ts +37 -0
- package/dist/integrations/corda-gateway/index.d.ts.map +1 -0
- package/dist/integrations/corda-gateway/index.js +234 -0
- package/dist/integrations/corda-gateway/ports.d.ts +33 -0
- package/dist/integrations/corda-gateway/ports.d.ts.map +1 -0
- package/dist/integrations/corda-gateway/ports.js +1 -0
- package/dist/integrations/fabric-gateway/index.d.ts +78 -0
- package/dist/integrations/fabric-gateway/index.d.ts.map +1 -0
- package/dist/integrations/fabric-gateway/index.js +214 -0
- package/dist/integrations/fabric-gateway/ports.d.ts +50 -0
- package/dist/integrations/fabric-gateway/ports.d.ts.map +1 -0
- package/dist/integrations/fabric-gateway/ports.js +1 -0
- package/dist/integrations/index.d.ts +19 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +19 -0
- package/dist/integrations/shared/env.d.ts +4 -0
- package/dist/integrations/shared/env.d.ts.map +1 -0
- package/dist/integrations/shared/env.js +24 -0
- package/dist/integrations/shared/retry.d.ts +79 -0
- package/dist/integrations/shared/retry.d.ts.map +1 -0
- package/dist/integrations/shared/retry.js +315 -0
- package/dist/mpc/adapters.d.ts +36 -0
- package/dist/mpc/adapters.d.ts.map +1 -0
- package/dist/mpc/adapters.js +46 -0
- package/dist/mpc/crypto.d.ts +2 -0
- package/dist/mpc/crypto.d.ts.map +1 -0
- package/dist/mpc/crypto.js +2 -0
- package/dist/mpc/dsa.d.ts +134 -0
- package/dist/mpc/dsa.d.ts.map +1 -0
- package/dist/mpc/dsa.js +127 -0
- package/dist/mpc/field.d.ts +127 -0
- package/dist/mpc/field.d.ts.map +1 -0
- package/dist/mpc/field.js +209 -0
- package/dist/mpc/hybrid-kem.d.ts +96 -0
- package/dist/mpc/hybrid-kem.d.ts.map +1 -0
- package/dist/mpc/hybrid-kem.js +136 -0
- package/dist/mpc/index.d.ts +135 -0
- package/dist/mpc/index.d.ts.map +1 -0
- package/dist/mpc/index.js +348 -0
- package/dist/mpc/kyber.d.ts +134 -0
- package/dist/mpc/kyber.d.ts.map +1 -0
- package/dist/mpc/kyber.js +143 -0
- package/dist/mpc/ports.d.ts +67 -0
- package/dist/mpc/ports.d.ts.map +1 -0
- package/dist/mpc/ports.js +9 -0
- package/dist/mpc/quantum.d.ts +80 -0
- package/dist/mpc/quantum.d.ts.map +1 -0
- package/dist/mpc/quantum.js +180 -0
- package/dist/p2mr/adapters.d.ts +31 -0
- package/dist/p2mr/adapters.d.ts.map +1 -0
- package/dist/p2mr/adapters.js +35 -0
- package/dist/p2mr/index.d.ts +63 -0
- package/dist/p2mr/index.d.ts.map +1 -0
- package/dist/p2mr/index.js +59 -0
- package/dist/p2mr/merkle-tree.d.ts +109 -0
- package/dist/p2mr/merkle-tree.d.ts.map +1 -0
- package/dist/p2mr/merkle-tree.js +239 -0
- package/dist/p2mr/p2mr-output.d.ts +142 -0
- package/dist/p2mr/p2mr-output.d.ts.map +1 -0
- package/dist/p2mr/p2mr-output.js +150 -0
- package/dist/p2mr/ports.d.ts +52 -0
- package/dist/p2mr/ports.d.ts.map +1 -0
- package/dist/p2mr/ports.js +9 -0
- package/dist/p2mr/script-interpreter.d.ts +92 -0
- package/dist/p2mr/script-interpreter.d.ts.map +1 -0
- package/dist/p2mr/script-interpreter.js +535 -0
- package/dist/p2mr/script-leaf.d.ts +70 -0
- package/dist/p2mr/script-leaf.d.ts.map +1 -0
- package/dist/p2mr/script-leaf.js +203 -0
- package/dist/p2mr/spend-proof.d.ts +95 -0
- package/dist/p2mr/spend-proof.d.ts.map +1 -0
- package/dist/p2mr/spend-proof.js +358 -0
- package/dist/p2mr/types.d.ts +209 -0
- package/dist/p2mr/types.d.ts.map +1 -0
- package/dist/p2mr/types.js +9 -0
- package/dist/privacy/application/view-projector.d.ts +13 -0
- package/dist/privacy/application/view-projector.d.ts.map +1 -0
- package/dist/privacy/application/view-projector.js +85 -0
- package/dist/privacy/domain/entities.d.ts +26 -0
- package/dist/privacy/domain/entities.d.ts.map +1 -0
- package/dist/privacy/domain/entities.js +1 -0
- package/dist/privacy/domain/ports.d.ts +7 -0
- package/dist/privacy/domain/ports.d.ts.map +1 -0
- package/dist/privacy/domain/ports.js +1 -0
- package/dist/privacy/index.d.ts +21 -0
- package/dist/privacy/index.d.ts.map +1 -0
- package/dist/privacy/index.js +25 -0
- package/dist/privacy/infrastructure/in-memory-store.d.ts +8 -0
- package/dist/privacy/infrastructure/in-memory-store.d.ts.map +1 -0
- package/dist/privacy/infrastructure/in-memory-store.js +7 -0
- package/dist/protocols/besu-port.d.ts +80 -0
- package/dist/protocols/besu-port.d.ts.map +1 -0
- package/dist/protocols/besu-port.js +1 -0
- package/dist/protocols/corda-port.d.ts +103 -0
- package/dist/protocols/corda-port.d.ts.map +1 -0
- package/dist/protocols/corda-port.js +9 -0
- package/dist/protocols/credentialing-port.d.ts +11 -0
- package/dist/protocols/credentialing-port.d.ts.map +1 -0
- package/dist/protocols/credentialing-port.js +1 -0
- package/dist/protocols/fabric-port.d.ts +89 -0
- package/dist/protocols/fabric-port.d.ts.map +1 -0
- package/dist/protocols/fabric-port.js +9 -0
- package/dist/protocols/index.d.ts +14 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/index.js +7 -0
- package/dist/protocols/p2mr-port.d.ts +159 -0
- package/dist/protocols/p2mr-port.d.ts.map +1 -0
- package/dist/protocols/p2mr-port.js +12 -0
- package/dist/protocols/privacy-port.d.ts +9 -0
- package/dist/protocols/privacy-port.d.ts.map +1 -0
- package/dist/protocols/privacy-port.js +1 -0
- package/dist/protocols/traceability-port.d.ts +12 -0
- package/dist/protocols/traceability-port.d.ts.map +1 -0
- package/dist/protocols/traceability-port.js +1 -0
- package/dist/shared/collection-store.d.ts +12 -0
- package/dist/shared/collection-store.d.ts.map +1 -0
- package/dist/shared/collection-store.js +26 -0
- package/dist/shared/commit.d.ts +24 -0
- package/dist/shared/commit.d.ts.map +1 -0
- package/dist/shared/commit.js +50 -0
- package/dist/shared/crypto.d.ts +2 -0
- package/dist/shared/crypto.d.ts.map +1 -0
- package/dist/shared/crypto.js +4 -0
- package/dist/shared/date.d.ts +2 -0
- package/dist/shared/date.d.ts.map +1 -0
- package/dist/shared/date.js +3 -0
- package/dist/shared/index.d.ts +9 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +11 -0
- package/dist/shared/logger.d.ts +37 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +45 -0
- package/dist/shared/store.d.ts +25 -0
- package/dist/shared/store.d.ts.map +1 -0
- package/dist/shared/store.js +18 -0
- package/dist/shared/telemetry-sdk.d.ts +26 -0
- package/dist/shared/telemetry-sdk.d.ts.map +1 -0
- package/dist/shared/telemetry-sdk.js +97 -0
- package/dist/shared/telemetry.d.ts +86 -0
- package/dist/shared/telemetry.d.ts.map +1 -0
- package/dist/shared/telemetry.js +137 -0
- package/dist/stark-settlement/application/aggregator-service.d.ts +112 -0
- package/dist/stark-settlement/application/aggregator-service.d.ts.map +1 -0
- package/dist/stark-settlement/application/aggregator-service.js +256 -0
- package/dist/stark-settlement/application/ledger-service.d.ts +114 -0
- package/dist/stark-settlement/application/ledger-service.d.ts.map +1 -0
- package/dist/stark-settlement/application/ledger-service.js +318 -0
- package/dist/stark-settlement/application/settlement-service.d.ts +104 -0
- package/dist/stark-settlement/application/settlement-service.d.ts.map +1 -0
- package/dist/stark-settlement/application/settlement-service.js +251 -0
- package/dist/stark-settlement/domain/entities.d.ts +365 -0
- package/dist/stark-settlement/domain/entities.d.ts.map +1 -0
- package/dist/stark-settlement/domain/entities.js +29 -0
- package/dist/stark-settlement/domain/ports.d.ts +485 -0
- package/dist/stark-settlement/domain/ports.d.ts.map +1 -0
- package/dist/stark-settlement/domain/ports.js +14 -0
- package/dist/stark-settlement/domain/value-objects.d.ts +268 -0
- package/dist/stark-settlement/domain/value-objects.d.ts.map +1 -0
- package/dist/stark-settlement/domain/value-objects.js +500 -0
- package/dist/stark-settlement/index.d.ts +172 -0
- package/dist/stark-settlement/index.d.ts.map +1 -0
- package/dist/stark-settlement/index.js +193 -0
- package/dist/stark-settlement/infrastructure/adapters/audit-adapter.d.ts +52 -0
- package/dist/stark-settlement/infrastructure/adapters/audit-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/audit-adapter.js +154 -0
- package/dist/stark-settlement/infrastructure/adapters/bitcoin-adapter.d.ts +88 -0
- package/dist/stark-settlement/infrastructure/adapters/bitcoin-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/bitcoin-adapter.js +187 -0
- package/dist/stark-settlement/infrastructure/adapters/clock-adapter.d.ts +59 -0
- package/dist/stark-settlement/infrastructure/adapters/clock-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/clock-adapter.js +85 -0
- package/dist/stark-settlement/infrastructure/adapters/dilithium-adapter.d.ts +60 -0
- package/dist/stark-settlement/infrastructure/adapters/dilithium-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/dilithium-adapter.js +104 -0
- package/dist/stark-settlement/infrastructure/adapters/event-emitter-adapter.d.ts +115 -0
- package/dist/stark-settlement/infrastructure/adapters/event-emitter-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/event-emitter-adapter.js +191 -0
- package/dist/stark-settlement/infrastructure/adapters/fiat-adapter.d.ts +65 -0
- package/dist/stark-settlement/infrastructure/adapters/fiat-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/fiat-adapter.js +207 -0
- package/dist/stark-settlement/infrastructure/adapters/mock-stark-adapter.d.ts +73 -0
- package/dist/stark-settlement/infrastructure/adapters/mock-stark-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/mock-stark-adapter.js +287 -0
- package/dist/stark-settlement/infrastructure/adapters/solana-adapter.d.ts +78 -0
- package/dist/stark-settlement/infrastructure/adapters/solana-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/solana-adapter.js +172 -0
- package/dist/stark-settlement/infrastructure/adapters/starknet-proof-adapter.d.ts +56 -0
- package/dist/stark-settlement/infrastructure/adapters/starknet-proof-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/starknet-proof-adapter.js +261 -0
- package/dist/stark-settlement/infrastructure/adapters/stone-proof-adapter.d.ts +125 -0
- package/dist/stark-settlement/infrastructure/adapters/stone-proof-adapter.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/adapters/stone-proof-adapter.js +416 -0
- package/dist/stark-settlement/infrastructure/persistence/ledger-store.d.ts +68 -0
- package/dist/stark-settlement/infrastructure/persistence/ledger-store.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/persistence/ledger-store.js +238 -0
- package/dist/stark-settlement/infrastructure/persistence/offset-store.d.ts +30 -0
- package/dist/stark-settlement/infrastructure/persistence/offset-store.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/persistence/offset-store.js +57 -0
- package/dist/stark-settlement/infrastructure/persistence/outbox-store.d.ts +45 -0
- package/dist/stark-settlement/infrastructure/persistence/outbox-store.d.ts.map +1 -0
- package/dist/stark-settlement/infrastructure/persistence/outbox-store.js +171 -0
- package/dist/traceability/application/recall-assessor.d.ts +13 -0
- package/dist/traceability/application/recall-assessor.d.ts.map +1 -0
- package/dist/traceability/application/recall-assessor.js +74 -0
- package/dist/traceability/domain/entities.d.ts +23 -0
- package/dist/traceability/domain/entities.d.ts.map +1 -0
- package/dist/traceability/domain/entities.js +1 -0
- package/dist/traceability/domain/ports.d.ts +23 -0
- package/dist/traceability/domain/ports.d.ts.map +1 -0
- package/dist/traceability/domain/ports.js +1 -0
- package/dist/traceability/domain/recall.d.ts +12 -0
- package/dist/traceability/domain/recall.d.ts.map +1 -0
- package/dist/traceability/domain/recall.js +1 -0
- package/dist/traceability/index.d.ts +22 -0
- package/dist/traceability/index.d.ts.map +1 -0
- package/dist/traceability/index.js +26 -0
- package/dist/traceability/infrastructure/in-memory-store.d.ts +13 -0
- package/dist/traceability/infrastructure/in-memory-store.d.ts.map +1 -0
- package/dist/traceability/infrastructure/in-memory-store.js +24 -0
- package/package.json +4 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* DEK/KEK envelope encryption — ephemeral DEK wrapped by a stored KEK.
|
|
4
|
+
*
|
|
5
|
+
* The resulting ciphertext is suitable for storage on a distributed ledger:
|
|
6
|
+
* - encryptedRecord = AES-256-GCM ciphertext of the payload
|
|
7
|
+
* - wrappedDek = GCM-wrapped DEK (only the HSM can unwrap it)
|
|
8
|
+
*/
|
|
9
|
+
export class EnvelopeEncryptionService {
|
|
10
|
+
symmetric;
|
|
11
|
+
audit;
|
|
12
|
+
constructor(symmetric, audit) {
|
|
13
|
+
this.symmetric = symmetric;
|
|
14
|
+
this.audit = audit;
|
|
15
|
+
}
|
|
16
|
+
encrypt(kekLabel, plaintext) {
|
|
17
|
+
const dek = randomBytes(32);
|
|
18
|
+
const payloadIv = randomBytes(12);
|
|
19
|
+
const payloadCipher = createCipheriv("aes-256-gcm", dek, payloadIv);
|
|
20
|
+
const ciphertextBuf = Buffer.concat([
|
|
21
|
+
payloadCipher.update(plaintext, "utf8"),
|
|
22
|
+
payloadCipher.final(),
|
|
23
|
+
]);
|
|
24
|
+
const payloadAuthTag = payloadCipher.getAuthTag();
|
|
25
|
+
const encryptedRecord = {
|
|
26
|
+
ciphertext: ciphertextBuf.toString("hex"),
|
|
27
|
+
iv: payloadIv.toString("hex"),
|
|
28
|
+
authTag: payloadAuthTag.toString("hex"),
|
|
29
|
+
algorithm: "aes-256-gcm",
|
|
30
|
+
};
|
|
31
|
+
const wrappedDek = this.symmetric.wrapKey(dek, kekLabel);
|
|
32
|
+
dek.fill(0);
|
|
33
|
+
this.audit.record("encryptWithEnvelope", kekLabel, "success");
|
|
34
|
+
return { encryptedRecord, wrappedDek };
|
|
35
|
+
}
|
|
36
|
+
decrypt(wrappedDek, encryptedRecord) {
|
|
37
|
+
const dek = this.symmetric.unwrapKey(wrappedDek);
|
|
38
|
+
const iv = Buffer.from(encryptedRecord.iv, "hex");
|
|
39
|
+
const authTag = Buffer.from(encryptedRecord.authTag, "hex");
|
|
40
|
+
const ciphertext = Buffer.from(encryptedRecord.ciphertext, "hex");
|
|
41
|
+
try {
|
|
42
|
+
const decipher = createDecipheriv("aes-256-gcm", dek, iv);
|
|
43
|
+
decipher.setAuthTag(authTag);
|
|
44
|
+
const plaintext = Buffer.concat([
|
|
45
|
+
decipher.update(ciphertext),
|
|
46
|
+
decipher.final(),
|
|
47
|
+
]).toString("utf8");
|
|
48
|
+
this.audit.record("decryptWithEnvelope", wrappedDek.kekLabel, "success");
|
|
49
|
+
return plaintext;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
this.audit.record("decryptWithEnvelope", wrappedDek.kekLabel, "failed", "GCM authentication failed");
|
|
53
|
+
throw new Error("HSM decryptWithEnvelope: GCM authentication failed");
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
dek.fill(0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { SymmetricKeyEntry, WrappedKey } from "../domain/entities.js";
|
|
2
|
+
import type { AuditLog, KeyStore } from "../domain/ports.js";
|
|
3
|
+
/**
|
|
4
|
+
* AES-256-GCM symmetric operations — key generation, wrapping, unwrapping.
|
|
5
|
+
*
|
|
6
|
+
* The raw key is stored as Uint8Array in the domain entity to enable
|
|
7
|
+
* explicit zeroization. In a production HSM the key never leaves
|
|
8
|
+
* hardware-protected storage. Do not persist or log the key bytes.
|
|
9
|
+
*
|
|
10
|
+
* SECURITY: Intermediate key buffers are zeroized after use to minimize
|
|
11
|
+
* key material exposure in memory.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SymmetricKeyService {
|
|
14
|
+
private readonly keyStore;
|
|
15
|
+
private readonly audit;
|
|
16
|
+
constructor(keyStore: KeyStore, audit: AuditLog);
|
|
17
|
+
generateSymmetricKey(keyLabel: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Wrap a DEK (data encryption key) using the KEK (key encryption key).
|
|
20
|
+
*
|
|
21
|
+
* SECURITY: The kekBuffer is zeroized after use.
|
|
22
|
+
*/
|
|
23
|
+
wrapKey(plaintextDek: Buffer, kekLabel: string): WrappedKey;
|
|
24
|
+
/**
|
|
25
|
+
* Unwrap a DEK using the KEK.
|
|
26
|
+
*
|
|
27
|
+
* SECURITY: The kekBuffer is zeroized after use.
|
|
28
|
+
* CALLER RESPONSIBILITY: The returned DEK buffer MUST be zeroized
|
|
29
|
+
* after use via `dekBuffer.fill(0)`.
|
|
30
|
+
*/
|
|
31
|
+
unwrapKey(wrapped: WrappedKey): Buffer;
|
|
32
|
+
requireSymmetric(kekLabel: string): SymmetricKeyEntry;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=symmetric-key-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symmetric-key-service.d.ts","sourceRoot":"","sources":["../../../src/hsm/application/symmetric-key-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;;;;;;;GASG;AACH,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,QAAQ;IAGlC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAc5C;;;;OAIG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IA6B3D;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM;IA8BtC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB;CAYtD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* AES-256-GCM symmetric operations — key generation, wrapping, unwrapping.
|
|
4
|
+
*
|
|
5
|
+
* The raw key is stored as Uint8Array in the domain entity to enable
|
|
6
|
+
* explicit zeroization. In a production HSM the key never leaves
|
|
7
|
+
* hardware-protected storage. Do not persist or log the key bytes.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY: Intermediate key buffers are zeroized after use to minimize
|
|
10
|
+
* key material exposure in memory.
|
|
11
|
+
*/
|
|
12
|
+
export class SymmetricKeyService {
|
|
13
|
+
keyStore;
|
|
14
|
+
audit;
|
|
15
|
+
constructor(keyStore, audit) {
|
|
16
|
+
this.keyStore = keyStore;
|
|
17
|
+
this.audit = audit;
|
|
18
|
+
}
|
|
19
|
+
generateSymmetricKey(keyLabel) {
|
|
20
|
+
if (this.keyStore.has(keyLabel)) {
|
|
21
|
+
throw new Error(`HSM key already exists: ${keyLabel}`);
|
|
22
|
+
}
|
|
23
|
+
this.keyStore.set(keyLabel, {
|
|
24
|
+
kind: "symmetric",
|
|
25
|
+
keyLabel,
|
|
26
|
+
// Buffer is a Uint8Array subclass; no copy needed
|
|
27
|
+
keyBytes: randomBytes(32),
|
|
28
|
+
createdAt: new Date().toISOString(),
|
|
29
|
+
});
|
|
30
|
+
this.audit.record("generateSymmetricKey", keyLabel, "success");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wrap a DEK (data encryption key) using the KEK (key encryption key).
|
|
34
|
+
*
|
|
35
|
+
* SECURITY: The kekBuffer is zeroized after use.
|
|
36
|
+
*/
|
|
37
|
+
wrapKey(plaintextDek, kekLabel) {
|
|
38
|
+
const kek = this.requireSymmetric(kekLabel);
|
|
39
|
+
const kekBuffer = Buffer.from(kek.keyBytes);
|
|
40
|
+
const iv = randomBytes(12);
|
|
41
|
+
try {
|
|
42
|
+
const cipher = createCipheriv("aes-256-gcm", kekBuffer, iv);
|
|
43
|
+
const wrappedDek = Buffer.concat([
|
|
44
|
+
cipher.update(plaintextDek),
|
|
45
|
+
cipher.final(),
|
|
46
|
+
]);
|
|
47
|
+
const authTag = cipher.getAuthTag();
|
|
48
|
+
this.audit.record("wrapKey", kekLabel, "success");
|
|
49
|
+
return {
|
|
50
|
+
algorithm: "aes-256-gcm",
|
|
51
|
+
wrappedDek: wrappedDek.toString("hex"),
|
|
52
|
+
iv: iv.toString("hex"),
|
|
53
|
+
authTag: authTag.toString("hex"),
|
|
54
|
+
kekLabel,
|
|
55
|
+
wrappedAt: new Date().toISOString(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
// Zeroize intermediate key material
|
|
60
|
+
kekBuffer.fill(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Unwrap a DEK using the KEK.
|
|
65
|
+
*
|
|
66
|
+
* SECURITY: The kekBuffer is zeroized after use.
|
|
67
|
+
* CALLER RESPONSIBILITY: The returned DEK buffer MUST be zeroized
|
|
68
|
+
* after use via `dekBuffer.fill(0)`.
|
|
69
|
+
*/
|
|
70
|
+
unwrapKey(wrapped) {
|
|
71
|
+
const kek = this.requireSymmetric(wrapped.kekLabel);
|
|
72
|
+
const kekBuffer = Buffer.from(kek.keyBytes);
|
|
73
|
+
const iv = Buffer.from(wrapped.iv, "hex");
|
|
74
|
+
const authTag = Buffer.from(wrapped.authTag, "hex");
|
|
75
|
+
const wrappedBuf = Buffer.from(wrapped.wrappedDek, "hex");
|
|
76
|
+
try {
|
|
77
|
+
const decipher = createDecipheriv("aes-256-gcm", kekBuffer, iv);
|
|
78
|
+
decipher.setAuthTag(authTag);
|
|
79
|
+
const plaintext = Buffer.concat([
|
|
80
|
+
decipher.update(wrappedBuf),
|
|
81
|
+
decipher.final(),
|
|
82
|
+
]);
|
|
83
|
+
this.audit.record("unwrapKey", wrapped.kekLabel, "success");
|
|
84
|
+
return plaintext;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
this.audit.record("unwrapKey", wrapped.kekLabel, "failed", "GCM authentication failed");
|
|
88
|
+
throw new Error("HSM unwrapKey: GCM authentication failed");
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
// Zeroize intermediate key material
|
|
92
|
+
kekBuffer.fill(0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
requireSymmetric(kekLabel) {
|
|
96
|
+
const entry = this.keyStore.get(kekLabel);
|
|
97
|
+
if (!entry) {
|
|
98
|
+
this.audit.record("keyLookup", kekLabel, "failed", "key not found");
|
|
99
|
+
throw new Error(`HSM key not found: ${kekLabel}`);
|
|
100
|
+
}
|
|
101
|
+
if (entry.kind !== "symmetric") {
|
|
102
|
+
this.audit.record("keyLookup", kekLabel, "failed", "unexpected key type");
|
|
103
|
+
throw new Error(`HSM key '${kekLabel}' is not a symmetric key`);
|
|
104
|
+
}
|
|
105
|
+
return entry;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSM Domain Entities
|
|
3
|
+
*
|
|
4
|
+
* These types define the HSM domain model. They MUST NOT depend on
|
|
5
|
+
* infrastructure types (like node:crypto KeyObject) to maintain
|
|
6
|
+
* hexagonal architecture purity.
|
|
7
|
+
*
|
|
8
|
+
* @see docs/adr/ADR-0001-hexagonal-architecture.md
|
|
9
|
+
*/
|
|
10
|
+
export interface HsmSlotConfig {
|
|
11
|
+
slotId: string;
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
export interface HsmKeyPair {
|
|
15
|
+
keyLabel: string;
|
|
16
|
+
keyType: "EC";
|
|
17
|
+
namedCurve: "P-256";
|
|
18
|
+
publicKeyPem: string;
|
|
19
|
+
privateKeyHandle: string;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
}
|
|
22
|
+
export interface HsmSignatureResult {
|
|
23
|
+
keyLabel: string;
|
|
24
|
+
algorithm: "ecdsa-sha256";
|
|
25
|
+
signature: string;
|
|
26
|
+
publicKeyPem: string;
|
|
27
|
+
timestamp: string;
|
|
28
|
+
hsmAttestation: string;
|
|
29
|
+
}
|
|
30
|
+
export interface WrappedKey {
|
|
31
|
+
algorithm: "aes-256-gcm";
|
|
32
|
+
wrappedDek: string;
|
|
33
|
+
iv: string;
|
|
34
|
+
authTag: string;
|
|
35
|
+
kekLabel: string;
|
|
36
|
+
wrappedAt: string;
|
|
37
|
+
}
|
|
38
|
+
export interface EncryptedRecord {
|
|
39
|
+
ciphertext: string;
|
|
40
|
+
iv: string;
|
|
41
|
+
authTag: string;
|
|
42
|
+
algorithm: "aes-256-gcm";
|
|
43
|
+
}
|
|
44
|
+
export interface EnvelopeEncryptionResult {
|
|
45
|
+
encryptedRecord: EncryptedRecord;
|
|
46
|
+
wrappedDek: WrappedKey;
|
|
47
|
+
}
|
|
48
|
+
export interface HsmAuditEntry {
|
|
49
|
+
timestamp: string;
|
|
50
|
+
operation: string;
|
|
51
|
+
keyLabel: string;
|
|
52
|
+
result: "success" | "failed";
|
|
53
|
+
detail?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Opaque handle for asymmetric keys.
|
|
57
|
+
*
|
|
58
|
+
* The domain should not know about the underlying key representation.
|
|
59
|
+
* The handle contains PEM-encoded keys which are portable and
|
|
60
|
+
* infrastructure-agnostic.
|
|
61
|
+
*/
|
|
62
|
+
export interface AsymmetricKeyHandle {
|
|
63
|
+
/** PEM-encoded private key (PKCS#8 format) */
|
|
64
|
+
privateKeyPem: string;
|
|
65
|
+
/** PEM-encoded public key (SPKI format) */
|
|
66
|
+
publicKeyPem: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Internal key store entry for asymmetric keys.
|
|
70
|
+
*
|
|
71
|
+
* Uses PEM strings instead of KeyObject to keep domain types
|
|
72
|
+
* infrastructure-agnostic. The infrastructure layer converts
|
|
73
|
+
* to/from KeyObject as needed.
|
|
74
|
+
*/
|
|
75
|
+
export interface AsymmetricKeyEntry {
|
|
76
|
+
kind: "asymmetric";
|
|
77
|
+
keyLabel: string;
|
|
78
|
+
/** PEM-encoded private key */
|
|
79
|
+
privateKeyPem: string;
|
|
80
|
+
/** PEM-encoded public key */
|
|
81
|
+
publicKeyPem: string;
|
|
82
|
+
namedCurve: "P-256";
|
|
83
|
+
createdAt: string;
|
|
84
|
+
}
|
|
85
|
+
export interface SymmetricKeyEntry {
|
|
86
|
+
kind: "symmetric";
|
|
87
|
+
keyLabel: string;
|
|
88
|
+
/**
|
|
89
|
+
* Raw key material as a byte array.
|
|
90
|
+
*
|
|
91
|
+
* Using Uint8Array instead of a base64 string enables explicit zeroization
|
|
92
|
+
* of in-memory key material. The infrastructure layer handles encoding/decoding
|
|
93
|
+
* at boundaries.
|
|
94
|
+
*
|
|
95
|
+
* SECURITY: This field represents the long-lived stored key material managed
|
|
96
|
+
* by the key store. Callers MUST NOT mutate or zeroize this buffer directly.
|
|
97
|
+
* Instead, create an ephemeral copy (e.g. `const key = Buffer.from(entry.keyBytes);`)
|
|
98
|
+
* for cryptographic operations, and securely zeroize that ephemeral copy after use.
|
|
99
|
+
*/
|
|
100
|
+
keyBytes: Uint8Array;
|
|
101
|
+
createdAt: string;
|
|
102
|
+
}
|
|
103
|
+
export type KeyEntry = AsymmetricKeyEntry | SymmetricKeyEntry;
|
|
104
|
+
//# sourceMappingURL=entities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../../src/hsm/domain/entities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,aAAa,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,QAAQ,GAAG,kBAAkB,GAAG,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSM Domain Entities
|
|
3
|
+
*
|
|
4
|
+
* These types define the HSM domain model. They MUST NOT depend on
|
|
5
|
+
* infrastructure types (like node:crypto KeyObject) to maintain
|
|
6
|
+
* hexagonal architecture purity.
|
|
7
|
+
*
|
|
8
|
+
* @see docs/adr/ADR-0001-hexagonal-architecture.md
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HsmAuditEntry, KeyEntry } from "./entities.js";
|
|
2
|
+
/**
|
|
3
|
+
* Port for the HSM key store — decouples domain services from storage.
|
|
4
|
+
*/
|
|
5
|
+
export interface KeyStore {
|
|
6
|
+
has(label: string): boolean;
|
|
7
|
+
get(label: string): KeyEntry | undefined;
|
|
8
|
+
set(label: string, entry: KeyEntry): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Port for the HSM audit log.
|
|
12
|
+
*
|
|
13
|
+
* Ref: NIST SP 800-57 Part 1, §8.1 — key management lifecycle auditing
|
|
14
|
+
* https://csrc.nist.gov/pubs/sp/800-57/pt1/r5/final
|
|
15
|
+
*/
|
|
16
|
+
export interface AuditLog {
|
|
17
|
+
record(operation: string, keyLabel: string, result: "success" | "failed", detail?: string): void;
|
|
18
|
+
entries(): readonly HsmAuditEntry[];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/hsm/domain/ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAAG,QAAQ,EAC5B,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAAC;IACR,OAAO,IAAI,SAAS,aAAa,EAAE,CAAC;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type { HsmSlotConfig, HsmKeyPair, HsmSignatureResult, WrappedKey, EncryptedRecord, EnvelopeEncryptionResult, HsmAuditEntry, } from "./domain/entities.js";
|
|
2
|
+
export type { KeyStore, AuditLog } from "./domain/ports.js";
|
|
3
|
+
export { AsymmetricKeyService } from "./application/asymmetric-key-service.js";
|
|
4
|
+
export { SymmetricKeyService } from "./application/symmetric-key-service.js";
|
|
5
|
+
export { EnvelopeEncryptionService } from "./application/envelope-encryption-service.js";
|
|
6
|
+
export { InMemoryAuditLog } from "./infrastructure/audit-log.js";
|
|
7
|
+
export { InMemoryKeyStore } from "./infrastructure/key-store.js";
|
|
8
|
+
export { FileAuditLog } from "./infrastructure/file-audit-log.js";
|
|
9
|
+
export type { ChainedAuditEntry } from "./infrastructure/file-audit-log.js";
|
|
10
|
+
export { SyslogAuditLog, DEFAULT_SYSLOG_CONFIG, } from "./infrastructure/syslog-audit-log.js";
|
|
11
|
+
export type { SyslogConfig, SyslogSeverity, SyslogFacility, } from "./infrastructure/syslog-audit-log.js";
|
|
12
|
+
export { AuditLogFactory, AUDIT_LOG_ENV, } from "./infrastructure/audit-log-factory.js";
|
|
13
|
+
export type { AuditLogType, AuditLogFactoryConfig, } from "./infrastructure/audit-log-factory.js";
|
|
14
|
+
import type { HsmSlotConfig, HsmKeyPair, HsmSignatureResult, WrappedKey, EncryptedRecord, EnvelopeEncryptionResult, HsmAuditEntry } from "./domain/entities.js";
|
|
15
|
+
/**
|
|
16
|
+
* Software simulation of a PKCS#11-style HSM.
|
|
17
|
+
*
|
|
18
|
+
* Private keys and raw symmetric material are stored inside the object and
|
|
19
|
+
* never returned to callers — only opaque handles or PEM public keys are
|
|
20
|
+
* surfaced externally. All operations are appended to an immutable audit log.
|
|
21
|
+
*
|
|
22
|
+
* Ref: PKCS#11 v3.1 — https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.1/pkcs11-curr-v3.1.html
|
|
23
|
+
*/
|
|
24
|
+
export declare class HsmClient {
|
|
25
|
+
private initialized;
|
|
26
|
+
private slotId;
|
|
27
|
+
private readonly store;
|
|
28
|
+
private readonly audit;
|
|
29
|
+
private asymmetric;
|
|
30
|
+
private symmetric;
|
|
31
|
+
private envelope;
|
|
32
|
+
initialize(config: HsmSlotConfig): void;
|
|
33
|
+
generateKeyPair(keyLabel: string): HsmKeyPair;
|
|
34
|
+
sign(keyLabel: string, data: string): HsmSignatureResult;
|
|
35
|
+
verify(keyLabel: string, data: string, signature: string): boolean;
|
|
36
|
+
exportPublicKey(keyLabel: string): string;
|
|
37
|
+
generateSymmetricKey(keyLabel: string): void;
|
|
38
|
+
wrapKey(plaintextDek: Buffer, kekLabel: string): WrappedKey;
|
|
39
|
+
unwrapKey(wrapped: WrappedKey): Buffer;
|
|
40
|
+
encryptWithEnvelope(kekLabel: string, plaintext: string): EnvelopeEncryptionResult;
|
|
41
|
+
decryptWithEnvelope(wrappedDek: WrappedKey, encryptedRecord: EncryptedRecord): string;
|
|
42
|
+
getAuditLog(): readonly HsmAuditEntry[];
|
|
43
|
+
private requireAsymmetric;
|
|
44
|
+
private requireSymmetric;
|
|
45
|
+
private requireEnvelope;
|
|
46
|
+
private assertInitialized;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hsm/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,wBAAwB,EACxB,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AAGzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EACL,cAAc,EACd,qBAAqB,GACtB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACV,YAAY,EACZ,cAAc,EACd,cAAc,GACf,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,aAAa,GACd,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EACV,YAAY,EACZ,qBAAqB,GACtB,MAAM,uCAAuC,CAAC;AAS/C,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,wBAAwB,EACxB,aAAa,EACd,MAAM,sBAAsB,CAAC;AAO9B;;;;;;;;GAQG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,QAAQ,CAA0C;IAE1D,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAwBvC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU;IAI7C,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAIxD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIlE,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIzC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI5C,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IAI3D,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM;IAItC,mBAAmB,CACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,wBAAwB;IAI3B,mBAAmB,CACjB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,eAAe,GAC/B,MAAM;IAIT,WAAW,IAAI,SAAS,aAAa,EAAE;IAIvC,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,iBAAiB;CAK1B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Application
|
|
2
|
+
export { AsymmetricKeyService } from "./application/asymmetric-key-service.js";
|
|
3
|
+
export { SymmetricKeyService } from "./application/symmetric-key-service.js";
|
|
4
|
+
export { EnvelopeEncryptionService } from "./application/envelope-encryption-service.js";
|
|
5
|
+
// Infrastructure
|
|
6
|
+
export { InMemoryAuditLog } from "./infrastructure/audit-log.js";
|
|
7
|
+
export { InMemoryKeyStore } from "./infrastructure/key-store.js";
|
|
8
|
+
export { FileAuditLog } from "./infrastructure/file-audit-log.js";
|
|
9
|
+
export { SyslogAuditLog, DEFAULT_SYSLOG_CONFIG, } from "./infrastructure/syslog-audit-log.js";
|
|
10
|
+
export { AuditLogFactory, AUDIT_LOG_ENV, } from "./infrastructure/audit-log-factory.js";
|
|
11
|
+
import { AsymmetricKeyService } from "./application/asymmetric-key-service.js";
|
|
12
|
+
import { SymmetricKeyService } from "./application/symmetric-key-service.js";
|
|
13
|
+
import { EnvelopeEncryptionService } from "./application/envelope-encryption-service.js";
|
|
14
|
+
import { InMemoryAuditLog } from "./infrastructure/audit-log.js";
|
|
15
|
+
import { InMemoryKeyStore } from "./infrastructure/key-store.js";
|
|
16
|
+
/**
|
|
17
|
+
* Software simulation of a PKCS#11-style HSM.
|
|
18
|
+
*
|
|
19
|
+
* Private keys and raw symmetric material are stored inside the object and
|
|
20
|
+
* never returned to callers — only opaque handles or PEM public keys are
|
|
21
|
+
* surfaced externally. All operations are appended to an immutable audit log.
|
|
22
|
+
*
|
|
23
|
+
* Ref: PKCS#11 v3.1 — https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.1/pkcs11-curr-v3.1.html
|
|
24
|
+
*/
|
|
25
|
+
export class HsmClient {
|
|
26
|
+
initialized = false;
|
|
27
|
+
slotId = "";
|
|
28
|
+
store = new InMemoryKeyStore();
|
|
29
|
+
audit = new InMemoryAuditLog();
|
|
30
|
+
asymmetric = null;
|
|
31
|
+
symmetric = null;
|
|
32
|
+
envelope = null;
|
|
33
|
+
initialize(config) {
|
|
34
|
+
if (config.slotId.trim().length === 0) {
|
|
35
|
+
throw new Error("HSM initialize: slotId must not be empty");
|
|
36
|
+
}
|
|
37
|
+
if (config.label.trim().length === 0) {
|
|
38
|
+
throw new Error("HSM initialize: label must not be empty");
|
|
39
|
+
}
|
|
40
|
+
if (this.initialized) {
|
|
41
|
+
throw new Error(`HSM already initialized on slot '${this.slotId}' — create a new HsmClient instance for a different slot`);
|
|
42
|
+
}
|
|
43
|
+
this.slotId = config.slotId;
|
|
44
|
+
this.asymmetric = new AsymmetricKeyService(this.store, this.audit, this.slotId);
|
|
45
|
+
this.symmetric = new SymmetricKeyService(this.store, this.audit);
|
|
46
|
+
this.envelope = new EnvelopeEncryptionService(this.symmetric, this.audit);
|
|
47
|
+
this.initialized = true;
|
|
48
|
+
this.audit.record("initialize", config.slotId, "success", config.label);
|
|
49
|
+
}
|
|
50
|
+
generateKeyPair(keyLabel) {
|
|
51
|
+
return this.requireAsymmetric().generateKeyPair(keyLabel);
|
|
52
|
+
}
|
|
53
|
+
sign(keyLabel, data) {
|
|
54
|
+
return this.requireAsymmetric().sign(keyLabel, data);
|
|
55
|
+
}
|
|
56
|
+
verify(keyLabel, data, signature) {
|
|
57
|
+
return this.requireAsymmetric().verify(keyLabel, data, signature);
|
|
58
|
+
}
|
|
59
|
+
exportPublicKey(keyLabel) {
|
|
60
|
+
return this.requireAsymmetric().exportPublicKey(keyLabel);
|
|
61
|
+
}
|
|
62
|
+
generateSymmetricKey(keyLabel) {
|
|
63
|
+
this.requireSymmetric().generateSymmetricKey(keyLabel);
|
|
64
|
+
}
|
|
65
|
+
wrapKey(plaintextDek, kekLabel) {
|
|
66
|
+
return this.requireSymmetric().wrapKey(plaintextDek, kekLabel);
|
|
67
|
+
}
|
|
68
|
+
unwrapKey(wrapped) {
|
|
69
|
+
return this.requireSymmetric().unwrapKey(wrapped);
|
|
70
|
+
}
|
|
71
|
+
encryptWithEnvelope(kekLabel, plaintext) {
|
|
72
|
+
return this.requireEnvelope().encrypt(kekLabel, plaintext);
|
|
73
|
+
}
|
|
74
|
+
decryptWithEnvelope(wrappedDek, encryptedRecord) {
|
|
75
|
+
return this.requireEnvelope().decrypt(wrappedDek, encryptedRecord);
|
|
76
|
+
}
|
|
77
|
+
getAuditLog() {
|
|
78
|
+
return this.audit.entries();
|
|
79
|
+
}
|
|
80
|
+
requireAsymmetric() {
|
|
81
|
+
this.assertInitialized();
|
|
82
|
+
return this.asymmetric;
|
|
83
|
+
}
|
|
84
|
+
requireSymmetric() {
|
|
85
|
+
this.assertInitialized();
|
|
86
|
+
return this.symmetric;
|
|
87
|
+
}
|
|
88
|
+
requireEnvelope() {
|
|
89
|
+
this.assertInitialized();
|
|
90
|
+
return this.envelope;
|
|
91
|
+
}
|
|
92
|
+
assertInitialized() {
|
|
93
|
+
if (!this.initialized) {
|
|
94
|
+
throw new Error("HSM not initialized: call initialize() first");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AuditLog } from "../domain/ports.js";
|
|
2
|
+
import { type SyslogConfig } from "./syslog-audit-log.js";
|
|
3
|
+
/**
|
|
4
|
+
* Audit log adapter types supported by the factory.
|
|
5
|
+
*/
|
|
6
|
+
export type AuditLogType = "memory" | "file" | "syslog";
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for creating audit log instances.
|
|
9
|
+
*/
|
|
10
|
+
export interface AuditLogFactoryConfig {
|
|
11
|
+
/** Type of audit log adapter. Default: "memory" */
|
|
12
|
+
type: AuditLogType;
|
|
13
|
+
/** File path for FileAuditLog (required when type is "file") */
|
|
14
|
+
filePath?: string;
|
|
15
|
+
/** Syslog configuration for SyslogAuditLog (optional when type is "syslog") */
|
|
16
|
+
syslogConfig?: Partial<SyslogConfig>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Environment variable names for audit log configuration.
|
|
20
|
+
*/
|
|
21
|
+
export declare const AUDIT_LOG_ENV: {
|
|
22
|
+
readonly TYPE: "HSM_AUDIT_LOG_TYPE";
|
|
23
|
+
readonly FILE_PATH: "HSM_AUDIT_LOG_PATH";
|
|
24
|
+
readonly SYSLOG_HOST: "HSM_SYSLOG_HOST";
|
|
25
|
+
readonly SYSLOG_PORT: "HSM_SYSLOG_PORT";
|
|
26
|
+
readonly SYSLOG_FACILITY: "HSM_SYSLOG_FACILITY";
|
|
27
|
+
readonly SYSLOG_APP_NAME: "HSM_SYSLOG_APP_NAME";
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Factory for creating audit log instances based on configuration.
|
|
31
|
+
*
|
|
32
|
+
* Supports three adapter types:
|
|
33
|
+
* - "memory": In-memory (default, for development/testing)
|
|
34
|
+
* - "file": Append-only file with cryptographic chaining
|
|
35
|
+
* - "syslog": RFC 5424 syslog for enterprise SIEM integration
|
|
36
|
+
*
|
|
37
|
+
* Configuration can be provided via:
|
|
38
|
+
* - Direct config object
|
|
39
|
+
* - Environment variables (for production)
|
|
40
|
+
*/
|
|
41
|
+
export declare class AuditLogFactory {
|
|
42
|
+
/**
|
|
43
|
+
* Create an audit log instance from explicit configuration.
|
|
44
|
+
*/
|
|
45
|
+
static create(config: AuditLogFactoryConfig): AuditLog;
|
|
46
|
+
/**
|
|
47
|
+
* Create an audit log instance from environment variables.
|
|
48
|
+
*
|
|
49
|
+
* Environment variables:
|
|
50
|
+
* - HSM_AUDIT_LOG_TYPE: "memory" | "file" | "syslog" (default: "memory")
|
|
51
|
+
* - HSM_AUDIT_LOG_PATH: file path for FileAuditLog
|
|
52
|
+
* - HSM_SYSLOG_HOST: syslog server hostname
|
|
53
|
+
* - HSM_SYSLOG_PORT: syslog server port
|
|
54
|
+
* - HSM_SYSLOG_FACILITY: syslog facility name
|
|
55
|
+
* - HSM_SYSLOG_APP_NAME: application name for syslog
|
|
56
|
+
*/
|
|
57
|
+
static createFromEnv(env?: NodeJS.ProcessEnv): AuditLog;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=audit-log-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log-factory.d.ts","sourceRoot":"","sources":["../../../src/hsm/infrastructure/audit-log-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,mDAAmD;IACnD,IAAI,EAAE,YAAY,CAAC;IACnB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,GAAG,QAAQ;IAuBtD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,QAAQ;CA8CrE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { InMemoryAuditLog } from "./audit-log.js";
|
|
2
|
+
import { FileAuditLog } from "./file-audit-log.js";
|
|
3
|
+
import { SyslogAuditLog } from "./syslog-audit-log.js";
|
|
4
|
+
/**
|
|
5
|
+
* Environment variable names for audit log configuration.
|
|
6
|
+
*/
|
|
7
|
+
export const AUDIT_LOG_ENV = {
|
|
8
|
+
TYPE: "HSM_AUDIT_LOG_TYPE",
|
|
9
|
+
FILE_PATH: "HSM_AUDIT_LOG_PATH",
|
|
10
|
+
SYSLOG_HOST: "HSM_SYSLOG_HOST",
|
|
11
|
+
SYSLOG_PORT: "HSM_SYSLOG_PORT",
|
|
12
|
+
SYSLOG_FACILITY: "HSM_SYSLOG_FACILITY",
|
|
13
|
+
SYSLOG_APP_NAME: "HSM_SYSLOG_APP_NAME",
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Factory for creating audit log instances based on configuration.
|
|
17
|
+
*
|
|
18
|
+
* Supports three adapter types:
|
|
19
|
+
* - "memory": In-memory (default, for development/testing)
|
|
20
|
+
* - "file": Append-only file with cryptographic chaining
|
|
21
|
+
* - "syslog": RFC 5424 syslog for enterprise SIEM integration
|
|
22
|
+
*
|
|
23
|
+
* Configuration can be provided via:
|
|
24
|
+
* - Direct config object
|
|
25
|
+
* - Environment variables (for production)
|
|
26
|
+
*/
|
|
27
|
+
export class AuditLogFactory {
|
|
28
|
+
/**
|
|
29
|
+
* Create an audit log instance from explicit configuration.
|
|
30
|
+
*/
|
|
31
|
+
static create(config) {
|
|
32
|
+
switch (config.type) {
|
|
33
|
+
case "memory":
|
|
34
|
+
return new InMemoryAuditLog();
|
|
35
|
+
case "file":
|
|
36
|
+
if (!config.filePath) {
|
|
37
|
+
throw new Error("AuditLogFactory: filePath is required when type is 'file'");
|
|
38
|
+
}
|
|
39
|
+
return new FileAuditLog(config.filePath);
|
|
40
|
+
case "syslog":
|
|
41
|
+
return new SyslogAuditLog(config.syslogConfig);
|
|
42
|
+
default:
|
|
43
|
+
throw new Error(`AuditLogFactory: unknown audit log type '${config.type}'`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create an audit log instance from environment variables.
|
|
48
|
+
*
|
|
49
|
+
* Environment variables:
|
|
50
|
+
* - HSM_AUDIT_LOG_TYPE: "memory" | "file" | "syslog" (default: "memory")
|
|
51
|
+
* - HSM_AUDIT_LOG_PATH: file path for FileAuditLog
|
|
52
|
+
* - HSM_SYSLOG_HOST: syslog server hostname
|
|
53
|
+
* - HSM_SYSLOG_PORT: syslog server port
|
|
54
|
+
* - HSM_SYSLOG_FACILITY: syslog facility name
|
|
55
|
+
* - HSM_SYSLOG_APP_NAME: application name for syslog
|
|
56
|
+
*/
|
|
57
|
+
static createFromEnv(env = process.env) {
|
|
58
|
+
const type = env[AUDIT_LOG_ENV.TYPE] || "memory";
|
|
59
|
+
const config = { type };
|
|
60
|
+
if (type === "file") {
|
|
61
|
+
const filePath = env[AUDIT_LOG_ENV.FILE_PATH];
|
|
62
|
+
if (filePath) {
|
|
63
|
+
config.filePath = filePath;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (type === "syslog") {
|
|
67
|
+
const syslogConfig = {};
|
|
68
|
+
const host = env[AUDIT_LOG_ENV.SYSLOG_HOST];
|
|
69
|
+
if (host) {
|
|
70
|
+
syslogConfig.host = host;
|
|
71
|
+
}
|
|
72
|
+
const port = env[AUDIT_LOG_ENV.SYSLOG_PORT];
|
|
73
|
+
if (port) {
|
|
74
|
+
const parsedPort = parseInt(port, 10);
|
|
75
|
+
if (!Number.isFinite(parsedPort) ||
|
|
76
|
+
!Number.isInteger(parsedPort) ||
|
|
77
|
+
parsedPort < 1 ||
|
|
78
|
+
parsedPort > 65535) {
|
|
79
|
+
throw new Error(`AuditLogFactory: invalid ${AUDIT_LOG_ENV.SYSLOG_PORT} value '${port}'. Expected an integer between 1 and 65535`);
|
|
80
|
+
}
|
|
81
|
+
syslogConfig.port = parsedPort;
|
|
82
|
+
}
|
|
83
|
+
const facility = env[AUDIT_LOG_ENV.SYSLOG_FACILITY];
|
|
84
|
+
if (facility) {
|
|
85
|
+
syslogConfig.facility = facility;
|
|
86
|
+
}
|
|
87
|
+
const appName = env[AUDIT_LOG_ENV.SYSLOG_APP_NAME];
|
|
88
|
+
if (appName) {
|
|
89
|
+
syslogConfig.appName = appName;
|
|
90
|
+
}
|
|
91
|
+
config.syslogConfig = syslogConfig;
|
|
92
|
+
}
|
|
93
|
+
return this.create(config);
|
|
94
|
+
}
|
|
95
|
+
}
|