Part of the node-message-broker build-out (Track B, Hub Plan 013 Phase 4). See .agents/plans/001-message-broker.md (local working doc).
Goal: node-to-node seal/open so the broker can encrypt outbound and decrypt inbound. The Hub never sees plaintext.
Steps
- New port
core/crypto/types.ts: ICryptoService { seal(plaintext, recipientPublicKey): Promise<string>; open(sealedBase64, senderPublicKey): Promise<Uint8Array> }.
- Adapter
adapters/crypto/kit-crypto-service.ts wrapping @privateaim/kit: sealMessage/openMessage (ECDH → per-message HKDF → AES-256-GCM). Reuse MESSAGE_SEAL_*; do not hand-roll AES/HKDF.
- Load the node private key once from
NODE_PRIVATE_KEY (hex-encoded PEM/SPKI → hexToUTF8 → importAsymmetricPrivateKey). Import peer public keys via hexToUTF8 → importAsymmetricPublicKey (cache by key string).
- Curve caveat: in-repo signal is P-256 but keys are operator-held — confirm a real provisioned node key's curve before locking; helpers are curve-agnostic.
Depends on: none.
Acceptance: seal(A)→open(B) round-trips over real generated keypairs; open throws on a tampered frame.
Part of the node-message-broker build-out (Track B, Hub Plan 013 Phase 4). See .agents/plans/001-message-broker.md (local working doc).
Goal: node-to-node seal/open so the broker can encrypt outbound and decrypt inbound. The Hub never sees plaintext.
Steps
core/crypto/types.ts:ICryptoService { seal(plaintext, recipientPublicKey): Promise<string>; open(sealedBase64, senderPublicKey): Promise<Uint8Array> }.adapters/crypto/kit-crypto-service.tswrapping@privateaim/kit:sealMessage/openMessage(ECDH → per-message HKDF → AES-256-GCM). ReuseMESSAGE_SEAL_*; do not hand-roll AES/HKDF.NODE_PRIVATE_KEY(hex-encoded PEM/SPKI →hexToUTF8→importAsymmetricPrivateKey). Import peer public keys viahexToUTF8→importAsymmetricPublicKey(cache by key string).Depends on: none.
Acceptance: seal(A)→open(B) round-trips over real generated keypairs;
openthrows on a tampered frame.